【LeetCode 经典题注】数组 & 链表

269 阅读2分钟

一、数组

1、两数之和

leetcode-cn.com/problems/tw…

解题思路:使用map作为缓存

  • 时间复杂度:O(n)

  • 空间复杂度:O(1)

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

2、三数之和

leetcode-cn.com/problems/3s…

解题思路:夹逼法

  • 时间复杂度:O(n)

  • 空间复杂度:O(1)

    class Solution { public List<List> threeSum(int[] nums) { List<List> result = new ArrayList<>(); Arrays.sort(nums); for (int k=0; k<nums.length-2; k++) { if (nums[k] > 0) break; if (k > 0 && nums[k] == nums[k - 1]) continue; int i = k+1, j = nums.length-1; while (i < j) { int sum = nums[k] + nums[i] + nums[j]; if (sum < 0) { while (i < j && nums[i] == nums[++i]); } else if (sum > 0) { while (i < j && nums[j] == nums[--j]); } else { result.add(Arrays.asList(nums[k], nums[i], nums[j])); while (i < j && nums[i] == nums[++i]); while (i < j && nums[j] == nums[--j]); } } } return result; } }

3、爬楼梯

leetcode-cn.com/problems/cl…

解题思路:用数组来保存斐波拉契序列

  • 时间复杂度:O(n)

  • 空间复杂度:O(n)

    class Solution { public int climbStairs(int n) { if (n == 1) return 1; int[] a = new int[n+1]; a[1] = 1; a[2] = 2; for (int i=3; i<=n; i++) { a[i] = a[i-1] + a[i-2]; } return a[n]; } }

4、合并两个有序数组

leetcode-cn.com/problems/me…

解题思路:双指针+从后往前复制

  • 时间复杂度:O(n)

  • 空间复杂度:O(1)

    class Solution { public void merge(int[] nums1, int m, int[] nums2, int n) { int p1 = m - 1; int p2 = n - 1; int p = m + n - 1; while (p1 >= 0 && p2 >= 0) { nums1[p--] = nums1[p1] > nums2[p2] ? nums1[p1--] : nums2[p2--]; } System.arraycopy(nums2, 0, nums1, 0, p2 + 1); } }

5、移动零

leetcode-cn.com/problems/mo…

解题思路:双指针法

  • 时间复杂度:O(n)

  • 空间复杂度:O(1)

    class Solution { public void moveZeroes(int[] nums) { for (int i = 0, j = 0; i < nums.length; i++) { if (nums[i] != 0) { nums[j] = nums[i]; if (i != j) { nums[i] = 0; } j++; } } } }

6、盛最多水的容器

leetcode-cn.com/problems/co…

解题思路:夹逼法

  • 时间复杂度:O(n)

  • 空间复杂度:O(1)

    class Solution { public int maxArea(int[] height) { int max = 0; for (int i=0, j=height.length-1; i<j; ) { int minHeight = height[i] < height[j] ? height[i++] : height[j--]; max = Math.max(max, minHeight * (j - i + 1)); } return max; } }

7、滑动窗口最大值

leetcode-cn.com/problems/sl…

解题思路:双端队列维持最大值

  • 时间复杂度:O(n)

  • 空间复杂度:O(k)

    class Solution { public int[] maxSlidingWindow(int[] nums, int k) { int[] result = new int[nums.length - k + 1]; Deque window = new LinkedList<>(); for (int i=0; i<nums.length; i++) { if (i >= k && window.peekLast() <= i - k) { window.pollLast(); } while (!window.isEmpty() && nums[window.peekFirst()] <= nums[i]) { window.pollFirst(); } window.addFirst(i); if (i >= k - 1) { result[i - k + 1] = nums[window.peekLast()]; } } return result; } }

8、柱状图中最大的矩形

leetcode-cn.com/problems/la…

解题思路:使用栈来记录左右边界,然后求面积最大值

  • 时间复杂度:O(n)

  • 空间复杂度:O(n)

    class Solution { public int largestRectangleArea(int[] heights) { int n = heights.length; int[] left = new int[n]; int[] right = new int[n]; Arrays.fill(right, n); Stack stack = new Stack<>(); for (int i=0; i<n; i++) { while (!stack.isEmpty() && heights[i] < heights[stack.peek()]) { right[stack.pop()] = i; } left[i] = stack.isEmpty() ? -1 : stack.peek(); stack.push(i); } int ans = 0; for (int i=0; i<n; i++) { ans = Math.max(ans, (right[i] - left[i] - 1) * heights[i]); } return ans; } }

9、接雨水

leetcode-cn.com/problems/tr…

解题思路:和上一题(柱状图中最大的矩形)类似,使用栈来记录左右边界

  • 时间复杂度:O(n)

  • 空间复杂度:O(n)

    class Solution { public int trap(int[] height) { Stack stack = new Stack<>(); int ans = 0; for (int i=0; i<height.length; i++) { while (!stack.isEmpty() && height[stack.peek()] < height[i]) { int top = stack.pop(); if (stack.isEmpty()) break; int instance = i - stack.peek() - 1; int hei = Math.min(height[i], height[stack.peek()]) - height[top]; ans += instance * hei; } stack.push(i); } return ans; } }

二、链表

leetcode-cn.com/problems/re…

1、反转链表

解题思路:利用pre节点驱动反转

  • 时间复杂度:O(n)

  • 空间复杂度:O(1)

    class Solution { public ListNode reverseList(ListNode head) { ListNode pre = null; ListNode cur = head; while(cur != null) { ListNode a = cur.next; cur.next = pre; pre = cur; cur = a; } return pre; } }

2、两两交换链表中的节点

leetcode-cn.com/problems/sw…

解题思路:理清节点交换思路即可

  • 时间复杂度:O(n)

  • 空间复杂度:O(1)

    class Solution { public ListNode swapPairs(ListNode head) { ListNode self = new ListNode(-1); ListNode prev = self; prev.next = head; ListNode cur = head; while(cur != null && cur.next != null) { ListNode first = cur.next; ListNode second = cur; cur = cur.next.next; prev.next = first; first.next = second; second.next = cur; prev = second; } return self.next; } }

3、K 个一组翻转链表

leetcode-cn.com/problems/re…

解题思路:综合链表反转,理清节点交换思路即可

  • 时间复杂度:O(n)

  • 空间复杂度:O(1)

    class Solution { public ListNode reverseKGroup(ListNode head, int k) { ListNode self = new ListNode(-1); self.next = head; ListNode pre = self; ListNode end = self; while (end.next != null) { for (int i=0; i<k && end != null; i++) { end = end.next; } if (end == null) break; ListNode next = end.next; end.next = null; ListNode start = pre.next; pre.next = reverse(start); start.next = next; pre = start; end = start; } return self.next; }

    private ListNode reverse(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        while (cur != null) {
            ListNode next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }
        return pre;
    }
    

    }