有趣的地方

有趣的地方

2024LeetCode分类刷题

一、数组

88. 合并两个有序数组
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int p1 = 0, p2 = 0;
        int[] sorted = new int[m + n];
        while (p1 < m || p2 < n) {
            int current;
            if (p1 == m) {
                current = nums2[p2++];
            } else if (p2 == n) {
                current = nums1[p1++];
            } else if (nums1[p1] < nums2[p2]) {
                current = nums1[p1++];
            } else {
                current = nums2[p2++];
            }
            sorted[p1 + p2 - 1] = current;
        }
        for (int i = 0; i < sorted.length; ++i) {
            nums1[i] = sorted[i];
        }
    }
27. 移除元素
    public int removeElement(int[] nums, int val) {
        int left = 0;
        for (int right = 0; right < nums.length; ++right) {
            if (nums[right] != val) {
                if (left != right) {
                    nums[left] = nums[right];
                }
                left++;
            }
        }
        return left;
    }
26. 删除有序数组中的重复项
    public int removeDuplicates(int[] nums) {
        int i = 1;
        for (int j = 1; j < nums.length; ++j) {
            if (nums[i - 1] != nums[j]) {
                nums[i] = nums[j];
                i++;
            }
        }
        return i;
    }
80. 删除有序数组中的重复项 II
    public int removeDuplicates(int[] nums) {
        if (nums.length < 2) {
            return nums.length;
        }
        int i = 2;
        for (int j = 2; j < nums.length; ++j) {
            if (nums[i - 2] != nums[j]) {
                nums[i] = nums[j];
                i++;
            }
        }
        return i;
    }
189. 轮转数组
    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);
    }

    private void reverse(int[] nums, int start, int end) {
        while (start < end) {
            int tmp = nums[start];
            nums[start] = nums[end];
            nums[end] = tmp;
            start++;
            end--;
        }
    }
15. 三数之和
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        if (nums.length == 0) {
            return result;
        }
        Arrays.sort(nums);
        for (int k = 0; k < nums.length - 2; ++k) {
            if (k > 0 && nums[k - 1] == nums[k]) {
                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[j] == nums[--j]) ;
                } else if (sum < 0) {
                    while (i < j && nums[i] == nums[++i]) ;
                } 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;
    }
66. 加一
    public int[] plusOne(int[] digits) {
        for (int i = digits.length - 1; i >= 0; --i) {
            digits[i] = (digits[i] + 1) % 10;
            if (digits[i] != 0) {
                return digits;
            }
        }
        digits = new int[digits.length + 1];
        digits[0] = 1;
        return digits;
    }
380. O(1) 时间插入、删除和获取随机元素
class RandomizedSet {
    private List<Integer> nums;
    private Map<Integer, Integer> indices;
    private Random random;

    public RandomizedSet() {
        this.nums = new ArrayList<>();
        this.indices = new HashMap<>();
        this.random = new Random();
    }

    public boolean insert(int val) {
        if (indices.containsKey(val)) {
            return false;
        }
        int index = nums.size();
        nums.add(val);
        indices.put(val, index);
        return true;
    }

    public boolean remove(int val) {
        if (!indices.containsKey(val)) {
            return false;
        }
        int index = indices.get(val);
        int last = nums.get(nums.size() - 1);
        nums.set(index, last);
        indices.put(last, index);
        nums.remove(nums.size() - 1);
        indices.remove(val);
        return true;
    }

    public int getRandom() {
        int randomIndex = random.nextInt(nums.size());
        return nums.get(randomIndex);
    }
}
238. 除自身以外数组的乘积
    public int[] productExceptSelf(int[] nums) {
        int[] left = new int[nums.length];
        int[] right = new int[nums.length];
        left[0] = 1;
        for (int i = 1; i < nums.length; ++i) {
            left[i] = left[i - 1] * nums[i - 1];
        }
        right[nums.length - 1] = 1;
        for (int i = nums.length - 2; i >= 0; --i) {
            right[i] = right[i + 1] * nums[i + 1];
        }
        int[] result = new int[nums.length];
        for (int i = 0; i < nums.length; ++i) {
            result[i] = left[i] * right[i];
        }
        return result;
    }
9. 回文数
    public boolean isPalindrome(int x) {
        if (x < 0 || (x % 10 == 0 && x != 0)) {
            return false;
        }
        int revertedNumber = 0;
        while (x > revertedNumber) {
            revertedNumber = revertedNumber * 10 + x % 10;
            x /= 10;
        }
        return x == revertedNumber || x == revertedNumber / 10;
    }
11. 盛最多水的容器
    public int maxArea(int[] height) {
        int maxArea = 0;
        for (int i = 0, j = height.length - 1; i < j; ) {
            int minHeight = height[i] < height[j] ? height[i++] : height[j--];
            maxArea = Math.max(maxArea, minHeight * (j - i + 1));
        }
        return maxArea;
    }
31. 下一个排列

思路:

  1. 先找出最大的索引i满足nums[i]<nums[i+1],如果不存在,就翻转整个数组
  2. 再找出另一个最大索引j满足nums[j]>nums[i]
  3. 交换nums[i]和nums[j]
  4. 最后翻转nums[i+1:]
    public void nextPermutation(int[] nums) {
        int i = nums.length - 2;
        while (i >= 0 && nums[i] >= nums[i + 1]) {
            i--;
        }
        if (i >= 0) {
            int j = nums.length - 1;
            while (j >= 0 && nums[i] >= nums[j]) {
                j--;
            }
            swap(nums, i, j);
        }
        reverse(nums, i + 1);
    }

    private void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }

    private void reverse(int[] nums, int i) {
        int j = nums.length - 1;
        while (i < j) {
            swap(nums, i, j);
            i++;
            j--;
        }
    }
54. 螺旋矩阵
    public List<Integer> spiralOrder(int[][] matrix) {
        List<Integer> result = new ArrayList<>();
        if (matrix.length == 0 || matrix[0].length == 0) {
            return result;
        }
        int left = 0, right = matrix[0].length - 1, up = 0, down = matrix.length - 1;
        while (true) {
            // 上
            for (int i = left; i <= right; ++i) {
                result.add(matrix[up][i]);
            }
            up++;
            if (up > down) {
                break;
            }
            // 右
            for (int i = up; i <= down; ++i) {
                result.add(matrix[i][right]);
            }
            right--;
            if (left > right) {
                break;
            }
            // 下
            for (int i = right; i >= left; --i) {
                result.add(matrix[down][i]);
            }
            down--;
            if (up > down) {
                break;
            }
            for (int i = down; i >= up; --i) {
                result.add(matrix[i][left]);
            }
            left++;
            if (left > right) {
                break;
            }
        }
        return result;
    }
56. 合并区间
    public int[][] merge(int[][] intervals) {
        Arrays.sort(intervals, (v1, v2) -> v1[0] - v2[0]);
        int[][] result = new int[intervals.length][2];
        int index = -1;
        for (int[] interval : intervals) {
            if (index == -1 || interval[0] > result[index][1]) {
                result[++index] = interval;
            } else {
                result[index][1] = Math.max(result[index][1], interval[1]);
            }
        }
        return Arrays.copyOf(result, index + 1);
    }

二、字符串

344. 反转字符串
    public void reverseString(char[] s) {
        int i = 0, j = s.length - 1;
        while (i < j) {
            char tmp = s[i];
            s[i] = s[j];
            s[j] = tmp;
            i++;
            j--;
        }
    }
415. 字符串相加
    public String addStrings(String num1, String num2) {
        StringBuilder result = new StringBuilder();
        int i = num1.length() - 1, j = num2.length() - 1, carry = 0;
        while (i >= 0 || j >= 0) {
            int n1 = i >= 0 ? num1.charAt(i) - '0' : 0;
            int n2 = j >= 0 ? num2.charAt(j) - '0' : 0;
            int tmp = n1 + n2 + carry;
            carry = tmp / 10;
            result.append(tmp % 10);
            i--;
            j--;
        }
        if (carry == 1) {
            result.append(1);
        }
        return result.reverse().toString();
    }
14. 最长公共前缀
    public String longestCommonPrefix(String[] strs) {
        if (strs == null || strs.length == 0) {
            return "";
        }
        for (int i = 0; i < strs[0].length(); ++i) {
            char c = strs[0].charAt(i);
            for (int j = 1; j < strs.length; ++j) {
                if (i == strs[j].length() || strs[j].charAt(i) != c) {
                    return strs[0].substring(0, i);
                }
            }
        }
        return strs[0];
    }
392. 判断子序列
    public boolean isSubsequence(String s, String t) {
        int i = 0, j = 0;
        while (i < s.length() && j < t.length()) {
            if (s.charAt(i) == t.charAt(j)) {
                i++;
            }
            j++;
        }
        return i >= s.length();
    }
165. 比较版本号
    public int compareVersion(String version1, String version2) {
        String[] v1 = version1.split("\\.");
        String[] v2 = version2.split("\\.");
        for (int i = 0; i < v1.length || i < v2.length; ++i) {
            int x = 0, y = 0;
            if (i < v1.length) {
                x = Integer.parseInt(v1[i]);
            }
            if (i < v2.length) {
                y = Integer.parseInt(v2[i]);
            }
            if (x > y) {
                return 1;
            }
            if (x < y) {
                return -1;
            }
        }
        return 0;
    }
58. 最后一个单词的长度
    public int lengthOfLastWord(String s) {
        int end = s.length() - 1;
        while (end >= 0 && s.charAt(end) == ' ') {
            end--;
        }
        if (end < 0) {
            return 0;
        }
        int start = end;
        while (start >= 0 && s.charAt(start) != ' ') {
            start--;
        }
        return end - start;
    }
151. 反转字符串中的单词
    public String reverseWords(String s) {
        String[] strs = s.trim().split(" ");
        StringBuilder res = new StringBuilder();
        for (int i = strs.length - 1; i >= 0; i--) {
            if (strs[i].equals("")) {
                continue;
            }
            res.append(strs[i] + " ");
        }
        return res.toString().trim();
    }

三、链表

常用解法及操作:

  • 快慢指针
  • 使用dummyNode
  • 链表反转
  • 找链表的中点
  • 获取链表节点的个数
2. 两数相加
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(-1);
        ListNode current = dummy;
        int carry = 0;
        while (l1 != null || l2 != null) {
            int p = l1 == null ? 0 : l1.val;
            int q = l2 == null ? 0 : l2.val;
            int sum = p + q + carry;
            carry = sum / 10;
            current.next = new ListNode(sum % 10);
            current = current.next;
            if (l1 != null) {
                l1 = l1.next;
            }
            if (l2 != null) {
                l2 = l2.next;
            }
        }
        if (carry > 0) {
            current.next = new ListNode(carry);
        }
        return dummy.next;
    }
21. 合并两个有序链表
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(-1);
        ListNode current = dummy;
        while (l1 != null && l2 != null) {
            if (l1.val < l2.val) {
                current.next = l1;
                l1 = l1.next;
            } else {
                current.next = l2;
                l2 = l2.next;
            }
            current = current.next;
        }
        if (l1 != null) {
            current.next = l1;
        }
        if (l2 != null) {
            current.next = l2;
        }
        return dummy.next;
    }
19. 删除链表的倒数第 N 个结点
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode fast = head, slow = head;
        for (int i = 0; i < n + 1; ++i) {
            if (fast == null) {
                return head.next;
            }
            fast = fast.next;
        }
        while (fast != null) {
            fast = fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;
        return head;
    }
160. 相交链表
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode pa = headA, pb = headB;
        while (pa != pb) {
            pa = pa == null ? headB : pa.next;
            pb = pb == null ? headA : pb.next;
        }
        return pa;
    }
83. 删除排序链表中的重复元素
    public ListNode deleteDuplicates(ListNode head) {
        ListNode current = head;
        while (current != null && current.next != null) {
            if (current.val == current.next.val) {
                current.next = current.next.next;
            } else {
                current = current.next;
            }
        }
        return head;
    }
82. 删除排序链表中的重复元素 II
    public ListNode deleteDuplicates(ListNode head) {
        if (head == null) {
            return head;
        }
        ListNode dummy = new ListNode(-1, head);
        ListNode current = dummy;
        while (current.next != null && current.next.next != null) {
            if (current.next.val == current.next.next.val) {
                int x = current.next.val;
                while (current.next != null && current.next.val == x) {
                    current.next = current.next.next;
                }
            } else {
                current = current.next;
            }
        }
        return dummy.next;
    }
141. 环形链表
    public boolean hasCycle(ListNode head) {
        ListNode fast = head, slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                return true;
            }
        }
        return false;
    }
142. 环形链表 II
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head, slow = head;
        boolean hasCycle = false;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                hasCycle = true;
                break;
            }
        }
        if (!hasCycle) {
            return null;
        }
        fast = head;
        while (fast != slow) {
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
206. 反转链表
    public ListNode reverseList(ListNode head) {
        ListNode pre = null, next = null;
        while (head != null) {
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        return pre;
    }
92. 反转链表 II
    public ListNode reverseBetween(ListNode head, int left, int right) {
        ListNode dummy = new ListNode(-1, head);
        ListNode preStart = dummy;
        for (int i = 0; i < left - 1; ++i) {
            preStart = preStart.next;
        }
        ListNode start = preStart.next;
        ListNode end = start;
        for (int i = 0; i < right - left; ++i) {
            end = end.next;
        }
        ListNode endNext = end.next;
        preStart.next = null;
        end.next = null;
        preStart.next = reverse(start);
        start.next = endNext;
        return dummy.next;
    }

    private ListNode reverse(ListNode node) {
        ListNode pre = null, next = null;
        while (node != null) {
            next = node.next;
            node.next = pre;
            pre = node;
            node = next;
        }
        return pre;
    }
25. K 个一组翻转链表
    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode dummy = new ListNode(-1, head);
        ListNode pre = dummy, end = dummy;
        while (end.next != null) {
            for (int i = 0; i < k && end != null; ++i) {
                end = end.next;
            }
            if (end == null) {
                break;
            }
            ListNode start = pre.next, endNext = end.next;
            pre.next = null;
            end.next = null;
            pre.next = reverse(start);
            start.next = endNext;
            pre = start;
            end = start;
        }
        return dummy.next;
    }

    private ListNode reverse(ListNode node) {
        ListNode pre = null, next = null;
        while (node != null) {
            next = node.next;
            node.next = pre;
            pre = node;
            node = next;
        }
        return pre;
    }
61. 旋转链表
    public ListNode rotateRight(ListNode head, int k) {
        if (head == null || head.next == null || k == 0) {
            return head;
        }
        ListNode current = head;
        int len = 0;
        while (current != null) {
            current = current.next;
            len++;
        }
        k = k % len;
        if (k == 0) {
            return head;
        }
        ListNode fast = head, slow = head;
        for (int i = 0; i < k + 1; ++i) {
            fast = fast.next;
        }
        while (fast != null) {
            fast = fast.next;
            slow = slow.next;
        }
        ListNode newHead = slow.next;
        slow.next = null;
        ListNode node = newHead;
        while (node.next != null) {
            node = node.next;
        }
        node.next = head;
        return newHead;
    }
86. 分隔链表
    public ListNode partition(ListNode head, int x) {
        if (head == null) {
            return head;
        }
        ListNode leftDummy = new ListNode(-1);
        ListNode left = leftDummy;
        ListNode rightDummy = new ListNode(-1);
        ListNode right = rightDummy;
        ListNode current = head;
        while (current != null) {
            if (current.val < x) {
                left.next = current;
                left = left.next;
            } else {
                right.next = current;
                right = right.next;
            }
            current = current.next;
        }
        right.next = null;
        left.next = rightDummy.next;
        return leftDummy.next;
    }
143. 重排链表
    public void reorderList(ListNode head) {
        if (head == null) {
            return;
        }
        ListNode mid = middleNode(head);
        ListNode l1 = head;
        ListNode l2 = mid.next;
        mid.next = null;
        l2 = reverseListNode(l2);
        mergeListNode(l1, l2);
    }

    private ListNode middleNode(ListNode head) {
        ListNode slow = head, fast = head;
        while (fast.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }

    private ListNode reverseListNode(ListNode node) {
        ListNode current = node, pre = null, next = null;
        while (current != null) {
            next = current.next;
            current.next = pre;
            pre = current;
            current = next;
        }
        return pre;
    }

    private void mergeListNode(ListNode l1, ListNode l2) {
        ListNode l1Tmp;
        ListNode l2Tmp;
        while (l1 != null && l2 != null) {
            l1Tmp = l1.next;
            l2Tmp = l2.next;
            l1.next = l2;
            l1 = l1Tmp;
            l2.next = l1;
            l2 = l2Tmp;
        }
    }

四、栈和队列

20. 有效的括号
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        char[] array = s.toCharArray();
        for (char c : array) {
            if (stack.isEmpty()) {
                stack.add(c);
            } else if (check(stack.peek(), c)) {
                stack.pop();
            } else {
                stack.add(c);
            }
        }
        return stack.isEmpty();
    }

    private boolean check(char c1, char c2) {
        return (c1 == '(' && c2 == ')') || (c1 == '{' && c2 == '}') || (c1 == '[' && c2 == ']');
    }
225. 用队列实现栈
class MyStack {
    private Queue<Integer> q1;
    private Queue<Integer> q2;
    private int top;

    public MyStack() {
        this.q1 = new LinkedList<>();
        this.q2 = new LinkedList<>();
    }

    public void push(int x) {
        top = x;
        q1.offer(x);
    }

    public int pop() {
        while (q1.size() > 1) {
            top = q1.poll();
            q2.offer(top);
        }
        int result = q1.poll();
        Queue<Integer> tmp = q1;
        q1 = q2;
        q2 = tmp;
        return result;
    }

    public int top() {
        return top;
    }

    public boolean empty() {
        return q1.isEmpty();
    }
}
232. 用栈实现队列
class MyQueue {

    private Stack<Integer> s1;
    private Stack<Integer> s2;
    private int front;

    public MyQueue() {
        s1 = new Stack<>();
        s2 = new Stack<>();
    }

    public void push(int x) {
        if (s1.isEmpty()) {
            front = x;
        }
        s1.push(x);
    }

    public int pop() {
        if (s2.isEmpty()) {
            while (!s1.isEmpty()) {
                s2.push(s1.pop());
            }
        }
        return s2.pop();
    }

    public int peek() {
        return s2.isEmpty() ? front : s2.peek();
    }

    public boolean empty() {
        return s1.isEmpty() && s2.isEmpty();
    }
}
155. 最小栈
class MinStack {
    private Stack<Integer> stack;
    private Stack<Integer> minStack;

    public MinStack() {
        this.stack = new Stack<>();
        this.minStack = new Stack<>();
    }

    public void push(int val) {
        stack.add(val);
        if (!minStack.isEmpty() && val > minStack.peek()) {
            minStack.add(minStack.peek());
        } else {
            minStack.add(val);
        }
    }

    public void pop() {
        stack.pop();
        minStack.pop();
    }

    public int top() {
        return stack.peek();
    }

    public int getMin() {
        return minStack.peek();
    }
}

五、堆

215. 数组中的第K个最大元素

思路:小顶堆

    public int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> queue = new PriorityQueue<>();
        for (int num : nums) {
            if (queue.size() < k) {
                queue.offer(num);
            } else if (queue.peek() < num) {
                queue.poll();
                queue.offer(num);
            }
        }
        return queue.peek();
    }

六、哈希表

3. 无重复字符的最长子串
    public int lengthOfLongestSubstring(String s) {
        int i = 0, j = 0, result = 0, n = s.length();
        Set<Character> set = new HashSet<>();
        while (i < n && j < n) {
            if (!set.contains(s.charAt(i))) {
                set.add(s.charAt(i++));
                result = Math.max(result, i - j);
            } else {
                set.remove(s.charAt(j++));
            }
        }
        return result;
    }
128. 最长连续序列
    public int longestConsecutive(int[] nums) {
        Set<Integer> numSet = new HashSet<>();
        for (int num : nums) {
            numSet.add(num);
        }
        int result = 0, seqLen = 0;
        for (int num : numSet) {
            if (!numSet.contains(num - 1)) {
                seqLen = 1;
                while (numSet.contains(++num)) {
                    seqLen++;
                }
                result = Math.max(seqLen, result);
            }
        }
        return result;
    }
1. 两数之和
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; ++i) {
            int temp = target - nums[i];
            if (map.containsKey(temp)) {
                return new int[]{i, map.get(temp)};
            }
            map.put(nums[i], i);
        }
        return new int[]{};
    }
169. 多数元素
    public int majorityElement(int[] nums) {
        Map<Integer, Integer> countMap = count(nums);
        Map.Entry<Integer, Integer> map = null;
        for (Map.Entry<Integer, Integer> entry : countMap.entrySet()) {
            if (map == null || entry.getValue() > map.getValue()) {
                map = entry;
            }
        }
        return map.getKey();
    }

    private Map<Integer, Integer> count(int[] nums) {
        Map<Integer, Integer> result = new HashMap<>();
        for (int num : nums) {
            result.put(num, result.getOrDefault(num, 0) + 1);
        }
        return result;
    }
242. 有效的字母异位词
    public boolean isAnagram(String s, String t) {
        if (s.length() != t.length()) {
            return false;
        }
        int[] array = new int[26];
        for (int i = 0; i < s.length(); ++i) {
            array[s.charAt(i) - 'a']++;
            array[t.charAt(i) - 'a']--;
        }
        for (int i : array) {
            if (i != 0) {
                return false;
            }
        }
        return true;
    }
49. 字母异位词分组
    public List<List<String>> groupAnagrams(String[] strs) {
        Map<String, List<String>> map = new HashMap<>();
        for (String str : strs) {
            char[] array = str.toCharArray();
            Arrays.sort(array);
            String s = String.valueOf(array);
            if (map.containsKey(s)) {
                map.get(s).add(str);
            } else {
                List<String> tmpList = new ArrayList<>();
                tmpList.add(str);
                map.put(s, tmpList);
            }
        }
        return new ArrayList<>(map.values());
    }
594. 最长和谐子序列
    public int findLHS(int[] nums) {
        Map<Integer, Integer> countMap = count(nums);
        int result = 0;
        for (int key : countMap.keySet()) {
            if (countMap.containsKey(key + 1)) {
                result = Math.max(result, countMap.get(key) + countMap.get(key + 1));
            }
        }
        return result;
    }

    private Map<Integer, Integer> count(int[] nums) {
        Map<Integer, Integer> result = new HashMap<>();
        for (int num : nums) {
            result.put(num, result.getOrDefault(num, 0) + 1);
        }
        return result;
    }

七、滑动窗口

209. 长度最小的子数组
    public int minSubArrayLen(int target, int[] nums) {
        int start = 0, end = 0, sum = 0, n = nums.length, result = Integer.MAX_VALUE;
        while (end < n) {
            sum += nums[end];
            while (sum >= target) {
                result = Math.min(end - start + 1, result);
                sum -= nums[start];
                start++;
            }
            end++;
        }
        return result == Integer.MAX_VALUE ? 0 : result;
    }

八、LRU Cache

146. LRU 缓存

思路:哈希表+双向链表

class LRUCache {
    private int capacity;
    private Map<Integer, Integer> cache;
    private LinkedList<Integer> keys;

    public LRUCache(int capacity) {
        this.capacity = capacity;
        this.cache = new HashMap<>();
        this.keys = new LinkedList<>();
    }

    public int get(int key) {
        if (!cache.containsKey(key)) {
            return -1;
        }
        int result = cache.get(key);
        put(key, result);
        return result;
    }

    public void put(int key, int value) {
        if (cache.containsKey(key)) {
            keys.remove((Integer) key);
        } else if (keys.size() >= capacity) {
            Integer old = keys.removeFirst();
            cache.remove(old);
        }
        cache.put(key, value);
        keys.addLast(key);
    }
}

九、二叉树

常用解法及操作:

  • 二叉树前中后序遍历
  • 二叉树层序遍历

完全二叉树的定义:

在这里插入图片描述

在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第h层,则该层包含1~ 2h个节点

二叉搜索树的定义:

在这里插入图片描述

  • 节点的左子树只包含小于当前节点的数
  • 节点的右子树只包含大于当前节点的数
  • 所有左子树和右子树自身必须也是二叉搜索树
104. 二叉树的最大深度
    public int maxDepth(TreeNode root) {
        if(root==null){
            return 0;
        }
        return Math.max(maxDepth(root.left),maxDepth(root.right))+1;
    }
100. 相同的树
    public boolean isSameTree(TreeNode p, TreeNode q) {
        if (p == null) {
            return q == null;
        }
        return q != null && p.val == q.val && isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
    }
226. 翻转二叉树
    public TreeNode invertTree(TreeNode root) {
        if (root == null) {
            return root;
        }
        TreeNode left = invertTree(root.left);
        TreeNode right = invertTree(root.right);
        root.left = right;
        root.right = left;
        return root;
    }
101. 对称二叉树
    public boolean isSymmetric(TreeNode root) {
        if (root == null) {
            return true;
        }
        return helper(root.left, root.right);
    }

    private boolean helper(TreeNode left, TreeNode right) {
        if (left == null && right == null) {
            return true;
        }
        if (left == null || right == null) {
            return false;
        }
        return left.val == right.val && helper(left.right, right.left) && helper(left.left, right.right);
    }
114. 二叉树展开为链表
    public void flatten(TreeNode root) {
        if (root == null) {
            return;
        }
        List<TreeNode> nodeList = new ArrayList<>();
        inorder(root, nodeList);
        for (int i = 1; i < nodeList.size(); ++i) {
            TreeNode last = nodeList.get(i - 1);
            TreeNode current = nodeList.get(i);
            last.left = null;
            last.right = current;
        }
    }

    private void inorder(TreeNode node, List<TreeNode> nodeList) {
        if (node == null) {
            return;
        }
        nodeList.add(node);
        inorder(node.left, nodeList);
        inorder(node.right, nodeList);
    }
112. 路径总和
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if (root == null) {
            return false;
        }
        if (root.left == null && root.right == null) {
            return root.val == targetSum;
        }
        return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val);
    }
129. 求根节点到叶节点数字之和
    public int sumNumbers(TreeNode root) {
        return helper(root, 0);
    }

    private int helper(TreeNode node, int preSum) {
        if (node == null) {
            return preSum;
        }
        int sum = preSum * 10 + node.val;
        if (node.left == null && node.right == null) {
            return sum;
        }
        return helper(node.left, sum) + helper(node.right, sum);
    }
124. 二叉树中的最大路径和
    Integer max = Integer.MIN_VALUE;

    public int maxPathSum(TreeNode root) {
        helper(root);
        return max;
    }

    private int helper(TreeNode node) {
        if (node == null) {
            return 0;
        }
        int left = helper(node.left);
        int right = helper(node.right);
        max = Math.max(max, node.val + left + right);
        return Math.max(0, node.val + Math.max(left, right));
    }
222. 完全二叉树的节点个数
    public int countNodes(TreeNode root) {
        if (root == null) {
            return 0;
        }
        return countNodes(root.left) + countNodes(root.right) + 1;
    }
236. 二叉树的最近公共祖先
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null || root == p || root == q) {
            return root;
        }
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        if (left == null) {
            return right;
        } else if (right == null) {
            return left;
        } else {
            return root;
        }
    }
117. 填充每个节点的下一个右侧节点指针 II
    public Node connect(Node root) {
        if (root == null) {
            return null;
        }
        LinkedList<Node> tmpList = new LinkedList<>();
        tmpList.add(root);
        while (!tmpList.isEmpty()) {
            int n = tmpList.size();
            Node last = null;
            for (int i = 0; i < n; ++i) {
                Node node = tmpList.poll();
                if (node.left != null) {
                    tmpList.add(node.left);
                }
                if (node.right != null) {
                    tmpList.add(node.right);
                }
                if (last != null) {
                    last.next = node;
                }
                last = node;
            }
        }
        return root;
    }
102. 二叉树的层序遍历
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        if (root == null) {
            return result;
        }
        LinkedList<TreeNode> tmpList = new LinkedList<>();
        tmpList.add(root);
        while (!tmpList.isEmpty()) {
            int n = tmpList.size();
            List<Integer> level = new ArrayList<>();
            for (int i = 0; i < n; ++i) {
                TreeNode node = tmpList.poll();
                level.add(node.val);
                if (node.left != null) {
                    tmpList.add(node.left);
                }
                if (node.right != null) {
                    tmpList.add(node.right);
                }
            }
            result.add(level);
        }
        return result;
    }
199. 二叉树的右视图

思路:二叉树层次遍历取最后一个

    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) {
            return result;
        }
        LinkedList<TreeNode> tmpList = new LinkedList<>();
        tmpList.add(root);
        while (!tmpList.isEmpty()) {
            int n = tmpList.size();
            for (int i = 0; i < n; ++i) {
                TreeNode node = tmpList.poll();
                if (node.left != null) {
                    tmpList.add(node.left);
                }
                if (node.right != null) {
                    tmpList.add(node.right);
                }
                if (i == n - 1) {
                    result.add(node.val);
                }
            }
        }
        return result;
    }
637. 二叉树的层平均值
    public List<Double> averageOfLevels(TreeNode root) {
        List<Double> result = new ArrayList<>();
        if (root == null) {
            return result;
        }
        LinkedList<TreeNode> tmpList = new LinkedList<>();
        tmpList.add(root);
        while (!tmpList.isEmpty()) {
            double sum = 0;
            int n = tmpList.size();
            for (int i = 0; i < n; ++i) {
                TreeNode node = tmpList.poll();
                sum += node.val;
                if (node.left != null) {
                    tmpList.add(node.left);
                }
                if (node.right != null) {
                    tmpList.add(node.right);
                }
            }
            result.add(sum / n);
        }
        return result;
    }
103. 二叉树的锯齿形层序遍历

思路:二叉树层次遍历,对应层翻转

    public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        if (root == null) {
            return result;
        }
        LinkedList<TreeNode> tmpList = new LinkedList<>();
        tmpList.add(root);
        while (!tmpList.isEmpty()) {
            int n = tmpList.size();
            List<Integer> levelList = new ArrayList<>();
            for (int i = 0; i < n; ++i) {
                TreeNode node = tmpList.poll();
                if (node.left != null) {
                    tmpList.add(node.left);
                }
                if (node.right != null) {
                    tmpList.add(node.right);
                }
                levelList.add(node.val);
            }
              if (result.size() % 2 == 1) {
                  Collections.reverse(levelList);
              }
              result.add(levelList);
        }
        return result;
    }
98. 验证二叉搜索树
    double last = -Double.MAX_VALUE;

    public boolean isValidBST(TreeNode root) {
        if (root == null) {
            return true;
        }
        if (isValidBST(root.left)) {
            if (last < root.val) {
                last = root.val;
                return isValidBST(root.right);
            }
        }
        return false;
    }
230. 二叉搜索树中第K小的元素
    List<Integer> tmpList = new ArrayList<>();

    public int kthSmallest(TreeNode root, int k) {
        helper(root);
        return tmpList.get(k - 1);
    }

    private void helper(TreeNode root) {
        if (root == null) {
            return;
        }
        helper(root.left);
        tmpList.add(root.val);
        helper(root.right);
    }
530. 二叉搜索树的最小绝对差
    int pre = -1;
    int result = Integer.MAX_VALUE;

    public int getMinimumDifference(TreeNode root) {
        helper(root);
        return result;
    }

    private void helper(TreeNode node) {
        if (node == null) {
            return;
        }
        helper(node.left);
        if (pre == -1) {
            pre = node.val;
        } else {
            result = Math.min(result, node.val - pre);
            pre = node.val;
        }
        helper(node.right);
    }
173. 二叉搜索树迭代器
class BSTIterator {

    private int index;
    private List<Integer> nodeValueList;

    public BSTIterator(TreeNode root) {
        this.index = 0;
        this.nodeValueList = new ArrayList<>();
        inorder(root, nodeValueList);
    }

    public int next() {
        return nodeValueList.get(index++);
    }

    public boolean hasNext() {
        return index < nodeValueList.size();
    }

    private void inorder(TreeNode node, List<Integer> tmpList) {
        if (node == null) {
            return;
        }
        inorder(node.left, tmpList);
        tmpList.add(node.val);
        inorder(node.right, tmpList);
    }
}

十、图

200. 岛屿数量

思路:

在这里插入图片描述

    public int numIslands(char[][] grid) {
        int m = grid.length, n = grid[0].length, count = 0;
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == '1') {
                    count++;
                    dfs(i, j, grid);
                }
            }
        }
        return count;
    }

    private void dfs(int i, int j, char[][] grid) {
        int m = grid.length, n = grid[0].length;
        if (i < 0 || j < 0 || i >= m || j >= n || grid[i][j] == '0') {
            return;
        }
        grid[i][j] = '0';
        dfs(i - 1, j, grid);
        dfs(i + 1, j, grid);
        dfs(i, j - 1, grid);
        dfs(i, j + 1, grid);
    }

十一、递归

递归模版代码:

public void recur(int level, int param) {
    //terminator(递归终止条件)
    if (level > MAX_LEVEL) {
        //process result 
        return;
    }
    //process current logic(处理当前层逻辑)
    process(level, param);
    //drill down(下探到下一层)
    recur(level + 1, newParam);
    //restore current status(清理当前层)
}
78. 子集
    List<List<Integer>> result = new ArrayList<>();

    public List<List<Integer>> subsets(int[] nums) {
        helper(0, new ArrayList<>(), nums);
        return result;
    }

    private void helper(int depth, List<Integer> tmpList, int[] nums) {
        result.add(new ArrayList<>(tmpList));
        for (int i = depth; i < nums.length; ++i) {
            tmpList.add(nums[i]);
            helper(i + 1, tmpList, nums);
            tmpList.remove(tmpList.size() - 1);
        }
    }
17. 电话号码的字母组合
    Map<Character, String> phone = new HashMap<Character, String>() {{
        put('2', "abc");
        put('3', "def");
        put('4', "ghi");
        put('5', "jkl");
        put('6', "mno");
        put('7', "pqrs");
        put('8', "tuv");
        put('9', "wxyz");
    }};
    List<String> result = new ArrayList<>();

    public List<String> letterCombinations(String digits) {
        if (digits.length() == 0) {
            return result;
        }
        helper(0, digits, "");
        return result;
    }

    private void helper(int depth, String digits, String currentStr) {
        if (depth == digits.length()) {
            result.add(currentStr);
            return;
        }
        String latters = phone.get(digits.charAt(depth));
        for (int i = 0; i < latters.length(); ++i) {
            helper(depth + 1, digits, currentStr + latters.charAt(i));
        }
    }
77. 组合
    List<List<Integer>> result = new ArrayList<>();

    public List<List<Integer>> combine(int n, int k) {
        helper(1, new ArrayList<>(), n, k);
        return result;
    }

    private void helper(int depth, List<Integer> tmpList, int n, int k) {
        if (tmpList.size() == k) {
            result.add(new ArrayList<>(tmpList));
            return;
        }
        for (int i = depth; i <= n; ++i) {
            tmpList.add(i);
            helper(i + 1, tmpList, n, k);
            tmpList.remove(tmpList.size() - 1);
        }
    }
46. 全排列
    List<List<Integer>> result = new ArrayList<>();

    public List<List<Integer>> permute(int[] nums) {
        int[] visited = new int[nums.length];
        helper(new ArrayList<>(), visited, nums);
        return result;
    }

    private void helper(List<Integer> tmpList, int[] visited, int[] nums) {
        if (tmpList.size() == nums.length) {
            result.add(new ArrayList<>(tmpList));
            return;
        }
        for (int i = 0; i < nums.length; ++i) {
            if (visited[i] == 1) {
                continue;
            }
            visited[i] = 1;
            tmpList.add(nums[i]);
            helper(tmpList, visited, nums);
            visited[i] = 0;
            tmpList.remove(tmpList.size() - 1);
        }
    }
47. 全排列 II
    private void helper(List<Integer> tmpList, int[] visited, int[] nums) {
        if (tmpList.size() == nums.length) {
            result.add(new ArrayList<>(tmpList));
            return;
        }
        for (int i = 0; i < nums.length; ++i) {
            if (visited[i] == 1) {
                continue;
            }
            if (i > 0 && nums[i] == nums[i - 1] && visited[i - 1] == 1) {
                continue;
            }
            visited[i] = 1;
            tmpList.add(nums[i]);
            helper(tmpList, visited, nums);
            visited[i] = 0;
            tmpList.remove(tmpList.size() - 1);
        }
    }
39. 组合总和
    List<List<Integer>> result = new ArrayList<>();

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        helper(0, new ArrayList<>(), candidates, target);
        return result;
    }

    private void helper(int depth, List<Integer> tmpList, int[] candidates, int target) {
        if (target < 0) {
            return;
        }
        if (target == 0) {
            result.add(new ArrayList<>(tmpList));
            return;
        }
        for (int i = depth; i < candidates.length; ++i) {
            tmpList.add(candidates[i]);
            helper(i, tmpList, candidates, target - candidates[i]);
            tmpList.remove(tmpList.size() - 1);
        }
    }
22. 括号生成
    List<String> result = new ArrayList<>();

    public List<String> generateParenthesis(int n) {
        helper(0, 0, "", n);
        return result;
    }

    private void helper(int left, int right, String currentStr, int n) {
        if (left == n && right == n) {
            result.add(currentStr);
            return;
        }
        if (left < n) {
            helper(left + 1, right, currentStr + "(", n);
        }
        if (right < left) {
            helper(left, right + 1, currentStr + ")", n);
        }
    }

十二、贪心算法

55. 跳跃游戏
    public boolean canJump(int[] nums) {
        int n = nums.length;
        if (n <= 1) {
            return true;
        }
        int step = 0;
        for (int i = 0; i < nums.length - 1; ++i) {
            step = Math.max(step, nums[i]);
            if (step + i >= nums.length - 1) {
                return true;
            }
            if (step == 0) {
                return false;
            }
            step--;
        }
        return false;
    }
45. 跳跃游戏 II
    public int jump(int[] nums) {
        int step = 0, end = 0, maxFar = 0;
        for (int i = 0; i < nums.length - 1; ++i) {
            maxFar = Math.max(maxFar, i + nums[i]);
            if (end == i) {
                end = maxFar;
                step++;
            }
        }
        return step;
    }
455. 分发饼干

思路:排序+双指针+贪心

    public int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);
        Arrays.sort(s);
        int m = g.length, n = s.length, result = 0;
        for (int i = 0, j = 0; i < m && j < n; ++i, ++j) {
            while (j < n && g[i] > s[j]) {
                j++;
            }
            if (j < n) {
                result++;
            }
        }
        return result;
    }

十三、二分查找

35. 搜索插入位置
    public int searchInsert(int[] nums, int target) {
        int low = 0, high = nums.length - 1, mid;
        while (low <= high) {
            mid = low + (high - low) / 2;
            if (nums[mid] > target) {
                high = mid - 1;
            } else if (nums[mid] < target) {
                low = mid + 1;
            } else {
                return mid;
            }
        }
        return low;
    }
33. 搜索旋转排序数组
    public int search(int[] nums, int target) {
        int low = 0, high = nums.length - 1;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            if (nums[mid] == target) {
                return mid;
            }
            if (nums[mid] >= nums[low]) {
                if (target >= nums[low] && target < nums[mid]) {
                    high = mid - 1;
                } else {
                    low = mid + 1;
                }
            } else {
                if (target > nums[mid] && target <= nums[high]) {
                    low = mid + 1;
                } else {
                    high = mid - 1;
                }
            }
        }
        return -1;
    }
852. 山脉数组的峰顶索引
    public int peakIndexInMountainArray(int[] arr) {
        int low = 1, high = arr.length - 2, result = 0;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            if (arr[mid] > arr[mid + 1]) {
                result = mid;
                high = mid - 1;
            } else {
                low = mid + 1;
            }
        }
        return result;
    }
540. 有序数组中的单一元素
    public int singleNonDuplicate(int[] nums) {
        int left = 0, right = nums.length - 1;
        while (left < right) {
            int mid = (left + right) / 2;
            if (mid % 2 == 0) {
                if (nums[mid] == nums[mid + 1]) {
                    left = mid + 1;
                } else {
                    right = mid;
                }
            } else {
                if (nums[mid] == nums[mid - 1]) {
                    left = mid + 1;
                } else {
                    right = mid;
                }
            }
        }
        return nums[right];
    }
162. 寻找峰值
    public int findPeakElement(int[] nums) {
        int n = nums.length;
        int left = 0, right = n - 1, result = -1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (compare(nums, mid - 1, mid) < 0 && compare(nums, mid, mid + 1) > 0) {
                result = mid;
                break;
            }
            if (compare(nums, mid, mid + 1) < 0) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return result;
    }

    private int compare(int[] nums, int index1, int index2) {
        int[] num1 = get(nums, index1);
        int[] num2 = get(nums, index2);
        if (num1[0] != num2[0]) {
            return num1[0] > num2[0] ? 1 : -1;
        }
        if (num1[1] == num2[1]) {
            return 0;
        }
        return num1[1] > num2[1] ? 1 : -1;
    }

    private int[] get(int[] nums, int idx) {
        if (idx == -1 || idx == nums.length) {
            return new int[]{0, 0};
        }
        return new int[]{1, nums[idx]};
    }

十四、一维动态规划

70. 爬楼梯
    public int climbStairs(int n) {
        if (n <= 2) {
            return n;
        }
        int[] dp = new int[n + 1];
        dp[1] = 1;
        dp[2] = 2;
        for (int i = 3; i <= n; ++i) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
121. 买卖股票的最佳时机
    public int maxProfit(int[] prices) {
        int min = Integer.MAX_VALUE;
        int max = 0;
        for (int price : prices) {
            min = Math.min(min, price);
            max = Math.max(max, price - min);
        }
        return max;
    }
122. 买卖股票的最佳时机 II
    public int maxProfit(int[] prices) {
        int result = 0;
        for (int i = 1; i < prices.length; ++i) {
            if (prices[i] - prices[i - 1] > 0) {
                result += prices[i] - prices[i - 1];
            }
        }
        return result;
    }
53. 最大子数组和

思路:dp[i]表示以nums[i]结尾的连续子数组的最大和

    public int maxSubArray(int[] nums) {
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        for (int i = 1; i < nums.length; ++i) {
            if (dp[i - 1] > 0) {
                dp[i] = nums[i] + dp[i - 1];
            } else {
                dp[i] = nums[i];
            }
        }
        int result = Integer.MIN_VALUE;
        for (int i = 0; i < dp.length; ++i) {
            result = Math.max(dp[i], result);
        }
        return result;
    }
152. 乘积最大子数组
    public int maxProduct(int[] nums) {
        int max = Integer.MIN_VALUE, imax = 1, imin = 1;
        for (int i = 0; i < nums.length; ++i) {
            if (nums[i] < 0) {
                int tmp = imax;
                imax = imin;
                imin = tmp;
            }
            imax = Math.max(imax * nums[i], nums[i]);
            imin = Math.min(imin * nums[i], nums[i]);
            max = Math.max(max, imax);
        }
        return max;
    }
300. 最长递增子序列
    public int lengthOfLIS(int[] nums) {
        if (nums.length == 0) {
            return 0;
        }
        int[] dp = new int[nums.length];
        int result = 0;
        for (int i = 0; i < nums.length; ++i) {
            dp[i] = 1;
            for (int j = 0; j < i; ++j) {
                if (nums[j] < nums[i]) {
                    dp[i] = Math.max(dp[j] + 1, dp[i]);
                }
            }
            result = Math.max(result, dp[i]);
        }
        return result;
    }
198. 打家劫舍
    public int rob(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        if (nums.length == 1) {
            return nums[0];
        }
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        dp[1] = Math.max(nums[0], nums[1]);
        for (int i = 2; i < nums.length; ++i) {
            dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
        }
        return dp[nums.length - 1];
    }
139. 单词拆分
    public boolean wordBreak(String s, List<String> wordDict) {
        Set<String> set = new HashSet<>(wordDict);
        boolean[] dp = new boolean[s.length() + 1];
        dp[0] = true;
        for (int i = 1; i <= s.length(); ++i) {
            for (int j = 0; j < i; ++j) {
                if (dp[j] && set.contains(s.substring(j, i))) {
                    dp[i] = true;
                    break;
                }
            }
        }
        return dp[s.length()];
    }
322. 零钱兑换
    public int coinChange(int[] coins, int amount) {
        int[] dp = new int[amount + 1];
        for (int i = 1; i <= amount; ++i) {
            int tmp = amount + 1;
            for (int coin : coins) {
                if (i >= coin) {
                    tmp = Math.min(tmp, dp[i - coin] + 1);
                }
            }
            dp[i] = tmp;
        }
        return dp[amount] == amount + 1 ? -1 : dp[amount];
    }

十五、二维动态规划

120. 三角形最小路径和
    public int minimumTotal(List<List<Integer>> triangle) {
        int n = triangle.size();
        int[][] dp = new int[n][n];
        dp[0][0] = triangle.get(0).get(0);
        for (int i = 1; i < triangle.size(); ++i) {
            dp[i][0] = dp[i - 1][0] + triangle.get(i).get(0);
            for (int j = 1; j < i; ++j) {
                dp[i][j] = Math.min(dp[i - 1][j], dp[i - 1][j - 1]) + triangle.get(i).get(j);
            }
            dp[i][i] = dp[i - 1][i - 1] + triangle.get(i).get(i);
        }
        int minTotal = dp[n - 1][0];
        for (int i = 1; i < n; ++i) {
            minTotal = Math.min(minTotal, dp[n - 1][i]);
        }
        return minTotal;
    }
64. 最小路径和
    public int minPathSum(int[][] grid) {
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (i == 0 && j == 0) {
                    continue;
                } else if (i == 0) {
                    grid[0][j] = grid[0][j - 1] + grid[i][j];
                } else if (j == 0) {
                    grid[i][0] = grid[i - 1][0] + grid[i][j];
                } else {
                    grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j];
                }
            }
        }
        return grid[grid.length - 1][grid[0].length - 1];
    }
63. 不同路径 II
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int m = obstacleGrid.length;
        if (m == 0 || obstacleGrid[0][0] == 1) {
            return 0;
        }
        obstacleGrid[0][0] = 1;
        int n = obstacleGrid[0].length;
        for (int i = 1; i < m; ++i) {
            obstacleGrid[i][0] = obstacleGrid[i - 1][0] == 1 && obstacleGrid[i][0] == 0 ? 1 : 0;
        }
        for (int j = 1; j < n; ++j) {
            obstacleGrid[0][j] = obstacleGrid[0][j - 1] == 1 && obstacleGrid[0][j] == 0 ? 1 : 0;
        }
        for (int i = 1; i < m; ++i) {
            for (int j = 1; j < n; ++j) {
                if (obstacleGrid[i][j] == 1) {
                    obstacleGrid[i][j] = 0;
                } else {
                    obstacleGrid[i][j] = obstacleGrid[i - 1][j] + obstacleGrid[i][j - 1];
                }
            }
        }
        return obstacleGrid[m - 1][n - 1];
    }
5. 最长回文子串
    public String longestPalindrome(String s) {
        int n = s.length();
        String result = "";
        boolean[][] dp = new boolean[n][n];
        for (int i = n - 1; i >= 0; --i) {
            for (int j = i; j < n; ++j) {
                if (j == i) {
                    dp[i][j] = true;
                } else if (j - i == 1 && s.charAt(i) == s.charAt(j)) {
                    dp[i][j] = true;
                } else if (s.charAt(i) == s.charAt(j) && dp[i + 1][j - 1]) {
                    dp[i][j] = true;
                }
                if (dp[i][j] && result.length() < j - i + 1) {
                    result = s.substring(i, j + 1);
                }
            }
        }
        return result;
    }
97. 交错字符串
    public boolean isInterleave(String s1, String s2, String s3) {
        int n = s1.length(), m = s2.length(), t = s3.length();
        if (n + m != t) {
            return false;
        }
        boolean[][] dp = new boolean[n + 1][m + 1];
        dp[0][0] = true;
        for (int i = 0; i <= n; ++i) {
            for (int j = 0; j <= m; ++j) {
                int p = i + j - 1;
                if (i > 0) {
                    dp[i][j] = (dp[i - 1][j] && s1.charAt(i - 1) == s3.charAt(p));
                }
                if (j > 0) {
                    dp[i][j] = dp[i][j] || (dp[i][j - 1] && s2.charAt(j - 1) == s3.charAt(p));
                }
            }
        }
        return dp[n][m];
    }
72. 编辑距离
    public int minDistance(String word1, String word2) {
        int[][] dp = new int[word1.length() + 1][word2.length() + 1];
        for (int i = 1; i < word1.length() + 1; ++i) {
            dp[i][0] = i;
        }
        for (int j = 1; j < word2.length() + 1; ++j) {
            dp[0][j] = j;
        }
        for (int i = 1; i < word1.length() + 1; ++i) {
            for (int j = 1; j < word2.length() + 1; ++j) {
                if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1];
                } else {
                    dp[i][j] = Math.min(Math.min(dp[i - 1][j - 1], dp[i - 1][j]), dp[i][j - 1]) + 1;
                }
            }
        }
        return dp[word1.length()][word2.length()];
    }
221. 最大正方形
    public int maximalSquare(char[][] matrix) {
        int maxSide = 0;
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return maxSide;
        }
        int m = matrix.length, n = matrix[0].length;
        int[][] dp = new int[m][n];
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (matrix[i][j] == '1') {
                    if (i == 0 || j == 0) {
                        dp[i][j] = 1;
                    } else {
                        dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i - 1][j], dp[i][j - 1])) + 1;
                    }
                }
                maxSide = Math.max(maxSide, dp[i][j]);
            }
        }
        return maxSide * maxSide;
    }

十六、排序算法

冒泡排序:

    public void bubbleSort(int[] nums, int n) {
        for (int i = 0; i < n; ++i) {
            boolean flag = false;
            for (int j = 0; j < n - i - 1; ++j) {
                if (nums[j + 1] < nums[j]) {
                    int tmp = nums[j];
                    nums[j] = nums[j + 1];
                    nums[j + 1] = tmp;
                    flag = true;
                }
            }
            if (!flag) {
                break;
            }
        }
    }

归并排序:

    public void mergeSort(int[] nums, int n) {
        mergeSortInternally(nums, 0, n - 1);
    }

    private void mergeSortInternally(int[] nums, int p, int r) {
        if (p >= r) return;
        int q = p + ((r - p) / 2);
        mergeSortInternally(nums, p, q);
        mergeSortInternally(nums, q + 1, r);
        merge(nums, p, q, r);
    }

    private void merge(int[] nums, int p, int q, int r) {
        int i = p;
        int j = q + 1;
        int k = 0;
        int[] tmp = new int[r - p + 1];
        while (i <= q && j <= r) {
            if (nums[i] <= nums[j]) {
                tmp[k++] = nums[i++];
            } else {
                tmp[k++] = nums[j++];
            }
        }
        int start = i;
        int end = q;
        if (j <= r) {
            start = j;
            end = r;
        }
        while (start <= end) {
            tmp[k++] = nums[start++];
        }
        for (i = 0; i < tmp.length; ++i) {
            nums[p + i] = tmp[i];
        }
    }

快速排序:

    public void quickSort(int[] nums, int p, int r) {
        if (p >= r) {
            return;
        }
        int q = partition(nums, p, r);
        quickSort(nums, p, q - 1);
        quickSort(nums, q + 1, r);
    }

    private int partition(int[] nums, int p, int r) {
        int pivot = nums[r];
        int i = p;
        for (int j = p; j < r; ++j) {
            if (nums[j] < pivot) {
                if (i != j) {
                    int tmp = nums[i];
                    nums[i] = nums[j];
                    nums[j] = tmp;
                }
                i++;
            }
        }
        nums[r] = nums[i];
        nums[i] = pivot;
        return i;
    }

发表评论:

Powered By Z-BlogPHP 1.7.3

© 2018-2020 有趣的地方 粤ICP备18140861号-1 网站地图