数组、链表、leetcode

434 阅读4分钟

self-summary-2020-02-04

数组

数组是一个线性表,存储相同数据结构的连续的内存空间。

数组的优劣

  • 优势
    • 随机访问时间复杂度为常数级别。

    • 支持cpu缓存,访问速度更加快速。(因为内存空间是连续的所以知道收地址的内存地址,cpu缓存就可以预读整个数组的所有数据。)
      • 一维数组的内存计算公式:a[i]address = base_address + (i-1)*data_type_size
      • 二维数组的内存计算公式: address = base_address + ( i * n + j) * type_size
  • 劣势
    • 删除慢
      • 删除一个数据需要进行数据搬移,是非常耗时的
      • 优化
        • 对删除的数据进行标记,不删除,当数组的存储空间不足的时候,在进行一次整体的删除操作,减少了搬移的次数(垃圾回收机制的标记清楚算法)
    • 插入慢
      • 插入数据的时候,数据搬移
      • 优化
        • 针对有序数组没发优化
        • 无序数组
          • 插入的新数据都插入末尾
          • 跟要插入的数据进行交换。
    • 大小有限,警惕数组索引越界(java.lang.ArrayIndexOutOfBoundsException)
  • 容器与数组的对比
    • 优势
      • 容器最大的优势就是1将数组的操作细节封装了起来。2.支持动态扩容。
    • 劣势
      • 容器不能存储基本数据类型
      • 数组效率高(知道数据大小的情况下)(底层开发数组的效率更高)
      • 多维情况下,数组更加直观

leetcode题目(移动零):

class Solution {
  	//first solution
 		//1.just find non-zero data 2.finally fill of all zero data.3.index is non-zero data's count.
    public void moveZeroes(int[] nums) {
      int index = 0;
      for(int num:nums){
          if(num!=0){
              nums[index++]=num;
          }
      }
      while(index<nums.length){
          nums[index++] = 0;
      }
    }
  	//second solution
  	//1.tow pointer ,first pointer is the first zero data's address,second pointer is the 			foreach count.
 		public void moveZeroesSecond(int[] nums){
      //first pointer
      int i = 0;
      //second pointer
      int j = 0;
      
      for(; j< nums.length; j++){
        //if nums[j] != 0 i++
        if( nums[j] != 0 ) {
          // exchage condition
          if( i != j){
            exchage(i,j,nums);
          }
          i++;
        }
      }
    }
 
   private void exchange(int[] nums, int i, int j) {
        nums[i] = nums[i] ^ nums[j];
        nums[j] = nums[i] ^ nums[j];
        nums[i] = nums[i] ^ nums[j];
    }
}

链表

链表的分类:

  • 单向链表
  • 双向链表
  • 循环链表
  • 静态链表

链表的优劣:

  • 优势
    • 删除,插入快
  • 劣势
    • 随机访问慢
    • 频繁的删除插入容易产生内存碎片,造成频繁的gc

链表实战

1.链表环形检测(leetcode):

//给定一个链表,判断链表中是否有环。 
//
// 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。 
//
// 
//
// 示例 1: 
//
// 输入:head = [3,2,0,-4], pos = 1
//输出:true
//解释:链表中有一个环,其尾部连接到第二个节点。
// 
//
// 
//
// 示例 2: 
//
// 输入:head = [1,2], pos = 0
//输出:true
//解释:链表中有一个环,其尾部连接到第一个节点。
// 
//
// 
//
// 示例 3: 
//
// 输入:head = [1], pos = -1
//输出:false
//解释:链表中没有环。
// 
//
// 
//
// 
//
// 进阶: 
//
// 你能用 O(1)(即,常量)内存解决此问题吗? 
// Related Topics 链表 双指针


//leetcode submit region begin(Prohibit modification and deletion)

//leetcode submit region end(Prohibit modification and deletion)



class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}



public class Solution {
  	// 1.fast pointer and slow pointer ,fast's start is one,every time two steps, slow's statr is zero , every time one step. if the fast catch catch up the slow,this list is cycle,else is no cycle. 
    public boolean hasCycle(ListNode head) {
         if(head == null){
             return false;
         }

         ListNode slow = head;
         ListNode fast = head.next;

         while(fast == null && fast.next == null){
            slow = slow.next;
            fast = fast.next.next;

            if(fast == slow){
                return true;
            }
         }
         return false;
    }
}



2.单链表反转

 /**
     * merge sorted list
     * @param l1
     * @param l2
     * @return
     */
    public LinkedList mergeTwoLists(LinkedList l1, LinkedList l2) {
        LinkedList solider = new LinkedList(0);
        LinkedList p  = solider;
        while(l1 != null && l2 != null) {
            if(l1.value <= l2.value) {
                p.next = l1;
                l1 = l1.next;
            }else{
                p.next = l2;
                l2 = l2.next;
            }
            p = p.next;
        }

        if(l1 == null) {
            p.next = l2;
        }
        if(l2 == null) {
            p.next = l1;
        }
        return solider.next;
    }

3.两个有序的链表合并

 /**
     * merge sorted list
     * @param l1
     * @param l2
     * @return
     */
    public LinkedList mergeTwoLists(LinkedList l1, LinkedList l2) {
        LinkedList solider = new LinkedList(0);
        LinkedList p  = solider;
        while(l1 != null && l2 != null) {
            if(l1.value <= l2.value) {
                p.next = l1;
                l1 = l1.next;
            }else{
                p.next = l2;
                l2 = l2.next;
            }
            p = p.next;
        }

        if(l1 == null) {
            p.next = l2;
        }
        if(l2 == null) {
            p.next = l1;
        }
        return solider.next;
    }

4.删除链表倒数第 n 个结点

 /**
     * delete the last k node
     * @param node
     */
     public void deletedTheLastKNode(LinkedList node,int k){

        LinkedList kNode = node;

        LinkedList preKNode = node;

        //node count.
        int count = 1;

        while(kNode != null){
           kNode = kNode.next;
           count++;
           if( count > k){
               preKNode  = preKNode.next;
           }
        }

        if(count == k){
            node = node.next;
        }
        if(count > k){
            preKNode.next = preKNode.next.next;
        }
     }

    /**
     * 
     * @param list
     * @param k
     * @return
     */
    public static LinkedList deleteLastKth(LinkedList list, int k) {
         LinkedList fast = list;
         int i = 1;
         while(fast !=null && i < k){
             fast = fast.next;
             i++;
         }

         if(fast == null) {
             return list;
         }

         LinkedList pre = null;
         LinkedList slow = list;

         while(fast.next != null){
             pre = slow;
             slow = slow.next;
             fast = fast.next;
         }

         if(pre == null){
             list = list.next;
         }else {
             pre.next = pre.next.next;
         }

         return list;

    }

5.求链表的中间结点

 /**
     * find list mid
     * @param head
     */
    private LinkedList findListMid(LinkedList head){
       if(head == null) {
           return null;
       }
       //fast pointer and slow pointer,if fast get the end slow's address is the mid's 		   address.

       LinkedList slow = head;

       LinkedList fast = head;

       while(fast != null && fast.next != null){
           slow = slow.next;
           fast = fast.next.next;
       }

       return slow;
    }