算法训练营第三课,数组/链表练习。

154 阅读1分钟

第三课

第一节 数组、链表和跳表的基本实现和特性

ArrayList 的添加和删除 源代码。

LinkedList

两个list相关时间和空间复杂度

question 100w 个数据 使用哪个比较快。

SkipList

跳表中心思想。

升维。空间换时间。

跳表:增加索引,增加多级索引。

image-20220112174042189

思想:空间换时间。 后面的树,二叉搜索树!都是基于这个思想。

O(logN)的时间复杂度。

空间复杂度:O(n)

n,n/2, n/4, n/8 ...

第二节 实战

练习步骤:

  1. 思考5-10mins!!!思考可能的题解,比较时间和空间复杂度。
  2. 有思路:自己开始做和写代码。否则看题解。
  3. 自己能默写、背诵。

练习题

1. 两数之和

class Solution {
    public int[] twoSum(int[] nums, int target) {
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            if (map.containsKey(nums[i])) {
                return new int[]{map.get(nums[i]), i};
            } else {
                map.put(target - nums[i], i);
            }
        }
        return null;
    }
}

15. 三数之和

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        if (nums == null || nums.length == 0) return res;
        Arrays.sort(nums);
        for (int i = 0; i < nums.length - 2; i++) {
            int low = i + 1, high = nums.length - 1;
            if (nums[i] > 0) break;
            if (i > 0 && nums[i] == nums[i - 1]) continue;
            int target = 0 - nums[i];
            while (low < high) {
                if (target == nums[low] + nums[high]) {
                    List<Integer> list = new ArrayList<>();
                    list.add(nums[i]);
                    list.add(nums[low]);
                    list.add(nums[high]);
                    res.add(list);
                    while (low < high && nums[low] == nums[low + 1]) {low++;}
                    while (low < high && nums[high] == nums[high - 1]) {high--;}
                    low++;
                    high--;
                } else if (target < nums[low] + nums[high]) {
                    high--;
                } else {
                    low++;
                }
            }
        }
        return res;
    }
}

189. 轮转数组

给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

示例 1:

输入: nums = [1,2,3,4,5,6,7], k = 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5,6] 向右轮转 2 步: [6,7,1,2,3,4,5] 向右轮转 3 步: [5,6,7,1,2,3,4]

// 我的简单思路
/*
1. 开辟新数组,把array[i + k % nums.length] = nums[i] 
*/
class Solution {
    public void rotate(int[] nums, int k) {
        int[] array = new int[nums.length];
        for (int i = 0; i < nums.length; i++) {
            array[(i + k) % nums.length] = nums[i];
        }
        for (int i = 0; i < nums.length; i++) {
            nums[i] = array[i];
        }
    }
}
// 老外
class Solution {
    public void rotate(int[] nums, int k) {
        k %= nums.length;
        reverse(nums, 0, nums.length - 1);
        reverse(nums, 0, k - 1);
        reverse(nums, k, nums.length - 1);
    }
    
    // 闭区间
    public void reverse(int[] nums, int left, int right) {
        while (left < right) {
            int temp = nums[left];
            nums[left] = nums[right];
            nums[right] = temp;
            left++;
            right--;
        }
    }
}

解释:

nums = "----->-->"; k =3
result = "-->----->";
​
reverse "----->-->" we can get "<--<-----"
reverse "<--" we can get "--><-----"
reverse "<-----" we can get "-->----->"
this visualization help me figure it out :)

21. 合并两个有序链表

24. 两两交换链表中的节点

public ListNode swapPairs(ListNode head) {
        ListNode dummy = new ListNode(-1, head);
        ListNode pre = dummy;
        ListNode cur = head;
        while (cur != null && cur.next != null) {
            ListNode nextNode = cur.next;
            cur.next = nextNode.next;
            nextNode.next = cur;
            pre.next = nextNode;
            pre = cur;
            cur = cur.next;
        }
        return dummy.next;
    }

\