codetop100-初篇

1.無重復(fù)字符的最長子串

??? #滑動(dòng)窗口 #雙指針

class Solution {
    public int lengthOfLongestSubstring(String s) {
        Set<Character> occ = new HashSet<>();
        int maxLength = 0, rk = -1;
        int n = s.length();
        for (int i = 0; i < n; i++) {
            if (i != 0) {
                occ.remove(s.charAt(i - 1));
            }
            while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) {
                occ.add(s.charAt(rk + 1));
                ++rk;
            }
            maxLength = Math.max(maxLength, rk - i + 1);
        }
        return maxLength;
    }
}
class Solution {
    public int lengthOfLongestSubstring(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        Set<Character> container = new HashSet<Character>();
        int n = s.length();
        int maxLength = 0;
        int j = 0;
        for (int i = 0; i < n; i++) {
            while (j < n && !container.contains(s.charAt(j))) {
                container.add(s.charAt(j));
                j++;
            }
            maxLength = Math.max(maxLength, j - i);
            container.remove(s.charAt(i));
        }
        return maxLength;
    }
}

2.LRU 緩存
??? #Java類庫
解法 1:復(fù)用 LinkedHashMap

class LRUCache extends LinkedHashMap<Integer, Integer>{

    private int capacity;

    public LRUCache(int capacity) {
        super(capacity, 0.75F, true);
        this.capacity = capacity;
    }
    
    public int get(int key) {
        return super.getOrDefault(key, -1);
    }
    
    public void put(int key, int value) {
        super.put(key, value);
    }

    public boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
        return size() > capacity;
    }
}

解法 2:手寫雙端鏈表

class LRUCache {

    private int size;
    private int capacity;
    private DLinkedNode head;
    private DLinkedNode tail;
    private Map<Integer, DLinkedNode> cache = new HashMap<Integer, DLinkedNode>();

    public LRUCache(int capacity) {
        this.size = 0;
        this.capacity = capacity;

        head = new DLinkedNode();
        tail = new DLinkedNode();
        head.next = tail;
        tail.pre = head;
    }

    public int get(int key) {
        DLinkedNode occNode = cache.get(key);
        if (occNode == null) {
            return -1;
        }
        moveToHead(occNode);
        return occNode.value;
    }

    public void put(int key, int value) {
        DLinkedNode occNode = cache.get(key);
        if (occNode == null) {
            DLinkedNode newNode = new DLinkedNode(key, value);
            cache.put(key, newNode);
            addToHead(newNode);
            ++size;
            if (size > capacity) {
                DLinkedNode tail = removeTail();
                cache.remove(tail.key);
                --size;
            }
        } else {
            occNode.value = value;
            moveToHead(occNode);
        }
    }

    class DLinkedNode {

        private int key;
        private int value;

        private DLinkedNode pre;
        private DLinkedNode next;

        public DLinkedNode() {
        }

        public DLinkedNode(int _key, int _value) {
            this.key = _key;
            this.value = _value;
        }
    }

    private void addToHead(DLinkedNode node) {
        node.next = head.next;
        node.pre = head;
        head.next.pre = node;
        head.next = node;
    }

    private void removeNode(DLinkedNode node) {
        node.pre.next = node.next;
        node.next.pre = node.pre;
    }

    private void moveToHead(DLinkedNode node) {
        removeNode(node);
        addToHead(node);
    }

    private DLinkedNode removeTail() {
        DLinkedNode res = tail.pre;
        removeNode(res);
        return res;
    }
}

3.反轉(zhuǎn)鏈表
??? #雙指針迭代

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

4.反轉(zhuǎn)鏈表 II
??? #雙指針迭代

class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {
        if (head == null || left == right) return head;
        
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode preLeft = dummy;
        
        // 定位到 left 的前一個(gè)節(jié)點(diǎn)
        for (int i = 1; i < left; i++) {
            preLeft = preLeft.next;
        }
        
        ListNode curr = preLeft.next;
        ListNode prev = null;
        ListNode next = null;
        ListNode tail = curr; // 記錄反轉(zhuǎn)后的尾節(jié)點(diǎn)
        
        // 反轉(zhuǎn) left 到 right 的節(jié)點(diǎn)
        for (int i = left; i <= right; i++) {
            next = curr.next;
            curr.next = prev;
            prev = curr;
            curr = next;
        }
        
        // 連接反轉(zhuǎn)后的子鏈表
        preLeft.next = prev;
        tail.next = curr;
        
        return dummy.next;
    }
}

5.數(shù)組中的第K個(gè)最大元素
解法 1:用 Java 類庫,Arrays.sort()
??? #Java類庫

class Solution {
    public int findKthLargest(int[] nums, int k) {
        Arrays.sort(nums);
        return nums[nums.length - k];
    }
}

解法 2:基于快速排序的選擇方法
??? #快速選擇排序

class Solution {

    private int quickSelect(int[] nums, int left, int right, int k) {
        if (left == right) {
            return nums[k];
        }

        int pivot = nums[left], i = left - 1, j = right + 1;
        while (i < j) {
            do
                i++;
            while (nums[i] < pivot);
            do
                j--;
            while (nums[j] > pivot);

            if (i < j) {
                swap(nums, i, j);
            }
        }
        if (k <= j)
            return quickSelect(nums, left, j, k);
        else
            return quickSelect(nums, j + 1, right, k);
    }

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

    public int findKthLargest(int[] nums, int k) {
        int n = nums.length;
        return quickSelect(nums, 0, n - 1, n - k);
    }
}

6.三數(shù)之和
??? #雙指針

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        if (nums == null || nums.length < 3) {
            return Collections.emptyList();
        }

        // 先排序
        Arrays.sort(nums);

        List<List<Integer>> resultList = new ArrayList<>();

        int n = nums.length;
        for (int i = 0; i < n; i++) {

            // 沒有符合條件的
            if (nums[i] > 0) {
                break;
            }

            // 排重
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }

            int left = i + 1;
            int right = n - 1;

            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                if (sum == 0) {
                    resultList.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    while (left < right && nums[left] == nums[left + 1]) {
                        left = left + 1;
                    }
                    while (left < right && nums[right] == nums[right - 1]) {
                        right = right - 1;
                    }

                    left = left + 1;
                    right = right - 1;
                } else if (sum > 0) {
                    right = right - 1;
                } else {
                    left = left + 1;
                }
            }
        }
        return resultList;
    }
}

7.最大子數(shù)組和
??? #動(dòng)態(tài)規(guī)劃

class Solution {
    public int maxSubArray(int[] nums) {
        int max = nums[0];
        int currentMax = nums[0];
        for (int i = 1; i < nums.length; i++) {
            currentMax = Math.max(nums[i], currentMax + nums[i]);
            max = Math.max(currentMax, max);
        }
        return max;
    }
}

8.合并兩個(gè)有序鏈表
??? #雙指針

/**
 * Definition for singly-linked list.
 * public class ListNode {
 * int val;
 * ListNode next;
 * ListNode() {}
 * ListNode(int val) { this.val = val; }
 * ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode preHead = new ListNode(-1);
        ListNode pre = preHead;
        while (l1 != null && l2 != null) {
            if (l1.val <= l2.val) {
                pre.next = l1;
                l1 = l1.next;
            } else {
                pre.next = l2;
                l2 = l2.next;
            }
            pre = pre.next;
        }
        pre.next = l1 == null ? l2 : l1;
        return preHead.next;
    }
}

9.最長回文子串
??? #中心擴(kuò)展算法

    public String longestPalindrome(String s) {
        if (s == null || s.length() < 1) {
            return "";
        }

        int start = 0, end = 0;
        for (int i = 0; i < s.length(); i++) {
            // 以i為中心的最長回文子串
            int len1 = expandAroundCenter(s, i, i);
            // 以i和i+1為中心的最長回文子串
            int len2 = expandAroundCenter(s, i, i + 1);
            int len = Math.max(len1, len2);
            if (len > end - start) {
                start = i - (len - 1) / 2;
                end = i + len / 2;
            }
        }
        return s.substring(start, end + 1);
    }

    private int expandAroundCenter(String s, int left, int right) {
        while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
            left--;
            right++;
        }
        // 返回以left+1和right-1為中心的回文串的長度
        return right - left - 1;
    }

10.二叉樹的層序遍歷
??? #廣度優(yōu)先遍歷

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 * int val;
 * TreeNode left;
 * TreeNode right;
 * TreeNode() {}
 * TreeNode(int val) { this.val = val; }
 * TreeNode(int val, TreeNode left, TreeNode right) {
 * this.val = val;
 * this.left = left;
 * this.right = right;
 * }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {

        if (root == null) {
            return new ArrayList();
        }

        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);

        List<List<Integer>> result = new ArrayList();
        while (!queue.isEmpty()) {
            List<Integer> currentLevel = new ArrayList();
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                TreeNode node = queue.poll();
                currentLevel.add(node.val);
                if (node.left != null) {
                    queue.offer(node.left);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                }
            }
            result.add(currentLevel);
        }
        return result;
    }
}

11.兩數(shù)之和
方案 1:暴力求解
??? #雙指針

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int n = nums.length;
        int[] result = new int[2];
        for (int i = 0; i < n; i++) {
            int j = i + 1;
            while (j < n) {
                if (nums[j] == target - nums[i]) {
                    result[0] = i;
                    result[1] = j;
                    break;
                } else {
                    j++;
                }
            }
        }
        return result;
    }
}

方案 2:Map 緩存
??? #哈希表優(yōu)化法(空間換時(shí)間)

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

12.搜索旋轉(zhuǎn)排序數(shù)組
??? #二分查找

class Solution {
    public int search(int[] nums, int target) {

        if(nums == null || nums.length == 0) {
            return -1;
        }

        int left = 0;
        int right = nums.length - 1;

        while(left <= right) {
            int middle = left + (right - left) / 2;
            if(target == nums[middle]) {
                return middle;
            }

            if(nums[left] <= nums[middle]) {
                if(target >= nums[left] && target < nums[middle]) {
                    right = middle - 1; 
                } else {
                    left = middle + 1;
                }
            } else {
                if(target > nums[middle] && target <= nums[right]) {
                    left = middle + 1;
                } else {
                    right = middle - 1;
                }
            }
        }
        return -1;
    }
}

13.島嶼數(shù)量
??? #深度優(yōu)先遍歷

public class NumIslands {

    public int numIslands(char[][] grid) {

        if (grid == null || grid.length == 0 || grid[0].length == 0) {
            return 0;
        }

        int rows = grid.length;
        int cols = grid[0].length;
        int count = 0;

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (grid[i][j] == '1') {
                    count++;
                    dfs(grid, i, j);
                }
            }
        }

        return count;
    }

    private void dfs(char[][] grid, int i, int j) {
        int rows = grid.length;
        int cols = grid[0].length;

        // 邊界檢查或者當(dāng)前位置已經(jīng)是水
        if (i < 0 || j < 0 || i >= rows || j >= cols || grid[i][j] == '0') {
            return;
        }

        // 將當(dāng)前陸地標(biāo)記為已訪問(變成水)
        grid[i][j] = '0';

        // 遞歸訪問上下左右四個(gè)方向
        dfs(grid, i + 1, j);
        dfs(grid, i - 1, j);
        dfs(grid, i, j + 1);
        dfs(grid, i, j - 1);
    }
}

14.全排列
??? #回溯

    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        if (nums == null || nums.length == 0) {
            return result;
        }
        boolean[] used = new boolean[nums.length];
        backtrack(result, new ArrayList<>(), nums, used);
        return result;
    }

    private void backtrack(List<List<Integer>> result, List<Integer> path, int[] nums, boolean[] used) {
        if (path.size() == nums.length) {
            result.add(new ArrayList<>(path));
            return;
        }

        for (int i = 0; i < nums.length; i++) {
            if (used[i]) {
                continue;
            }
            used[i] = true;
            path.add(nums[i]);
            backtrack(result, path, nums, used);
            path.remove(path.size() - 1);
            used[i] = false;
        }
    }

15.買賣股票的最佳時(shí)機(jī)
??? #動(dòng)態(tài)規(guī)劃

    public int maxProfit(int[] prices) {
        if(prices == null || prices.length == 0) {
            return 0;
        }
        int minPrice = prices[0];
        int maxProfit = 0;
        for(int i = 1; i < prices.length; i++) {
            if(prices[i] < minPrice) {
                minPrice = prices[i];
            } else {
                maxProfit = Math.max(maxProfit, prices[i] - minPrice);
            }
        }
        return maxProfit;
    }

16.有效的括號
??? #棧 #線性遍歷

    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(' || s.charAt(i) == '[' || s.charAt(i) == '{') {
                stack.push(s.charAt(i));
            } else {
                if (stack.isEmpty()) {
                    return false;
                }

                Character top = stack.pop();
                if (s.charAt(i) == ')' && top != '(') {
                    return false;
                }

                if (s.charAt(i) == '}' && top != '{') {
                    return false;
                }

                if (s.charAt(i) == ']' && top != '[') {
                    return false;
                }
            }
        }
        return stack.isEmpty();
    }
public boolean isValid(String s) {
        int n = s.length();
        if (n % 2 == 1) {
            return false;
        }

        Map<Character, Character> pairs = new HashMap<Character, Character>() {
            {
                put(')', '(');
                put(']', '[');
                put('}', '{');
            }
        };

        Stack<Character> stack = new Stack();
        for (int i = 0; i < n; i++) {
            Character ch = s.charAt(i);
            if (pairs.containsKey(ch)) {
                if (stack.isEmpty() || pairs.get(ch) != stack.peek()) {
                    return false;
                }
                stack.pop();
            } else {
                stack.push(ch);
            }
        }
        return stack.isEmpty();
    }

17.二叉樹的最近公共祖先
??? #遞歸分治 #后序遍歷

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    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;
        }
        if(right == null) {
            return left;
        }
        return root;
    }
}

18.環(huán)形鏈表
??? #快慢指針 #雙指針

/**
 * Definition for singly-linked list.
 * class ListNode {
 * int val;
 * ListNode next;
 * ListNode(int x) {
 * val = x;
 * next = null;
 * }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {

        if (head == null || head.next == null) {
            return false;
        }

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

        while (slow != fast) {
            if (fast == null || fast.next == null) {
                return false;
            }
            slow = slow.next;
            fast = fast.next.next;
        }
        return true;
    }
}
public class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null) {
            return false;
        }
        ListNode slow = head;
        ListNode fast = head.next;
        while (fast != null && fast.next != null && slow != fast) {
            slow = slow.next;
            fast = fast.next.next;
        }
        return fast == slow;
    }
}

19.合并 K 個(gè)升序鏈表
??? #分治法 #歸并排序

/**
 * Definition for singly-linked list.
 * public class ListNode {
 * int val;
 * ListNode next;
 * ListNode() {}
 * ListNode(int val) { this.val = val; }
 * ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) {
            return null;
        }

        return merge(lists, 0, lists.length - 1);
    }

    private ListNode merge(ListNode[] lists, int l, int r) {
        if (l == r) {
            return lists[l];
        }

        if (l > r) {
            return null;
        }

        int middle = (l + r) >> 1;
        return mergeTwoLists(merge(lists, l, middle), merge(lists, middle + 1, r));
    }

    private ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if (l1 == null) {
            return l2;
        }

        if (l2 == null) {
            return l1;
        }

        if (l1.val <= l2.val) {
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        } else {
            l2.next = mergeTwoLists(l1, l2.next);
            return l2;
        }
    }
}
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) {
            return null;
        }
        return mergeKLists(lists, 0, lists.length - 1);
    }

    private ListNode mergeKLists(ListNode[] lists, int l, int r) {
        if (l == r) {
            return lists[l];
        }

        int middle = l + (r - l) / 2;
        ListNode left = mergeKLists(lists, l, middle);
        ListNode right = mergeKLists(lists, middle + 1, r);

        return mergeTwoList(left, right);
    }

    private ListNode mergeTwoList(ListNode left, ListNode right) {
        ListNode dummy = new ListNode(-1);
        ListNode pre = dummy;

        while (left != null && right != null) {
            if (left.val <= right.val) {
                pre.next = left;
                left = left.next;
            } else {
                pre.next = right;
                right = right.next;
            }
            pre = pre.next;
        }
        pre.next = left != null ? left : right;
        return dummy.next;
    }
}

20.最長遞增子序列
??? #動(dòng)態(tài)規(guī)劃

class Solution {
    public int lengthOfLIS(int[] nums) {
        
        if(nums == null || nums.length == 0) {
            return 0;
        }

        int[] dp = new int[nums.length];

        dp[0] = 1;
        int maxLength = 1;

        for(int i=1; i<nums.length; i++) {
            dp[i] = 1;
            for(int j=0; j<i; j++) {
                if(nums[i] > nums[j]) {
                    dp[i] = Math.max(dp[j] + 1, dp[i]);
                }
            }
            maxLength = Math.max(dp[i], maxLength);
        }
        return maxLength;
    }
}

21.相交鏈表
??? #雙指針 #數(shù)學(xué)路徑

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if(headA == null || headB == null) {
            return null;
        }
        ListNode p1 = headA;
        ListNode p2 = headB;
        while(p1 != p2) {
            p1 = (p1 == null) ? headB : p1.next;
            p2 = (p2 == null) ? headA : p2.next;
        }
        return p1;
    }
}

22.合并區(qū)間
??? #預(yù)排序 #貪心算法 #線性遍歷

    public int[][] merge(int[][] intervals) {
        if (intervals == null || intervals.length <= 1) {
            return intervals;
        }

        // 按照區(qū)間起點(diǎn)進(jìn)行排序
        Arrays.sort(intervals, (a, b) -> a[0] - b[0]);

        List<int[]> merged = new ArrayList<>();
        int[] current = intervals[0];
        merged.add(current);

        for (int i = 1; i < intervals.length; i++) {
            int[] interval = intervals[i];
            // 當(dāng)前區(qū)間的起點(diǎn)小于等于上一個(gè)區(qū)間的終點(diǎn),說明重疊
            if (interval[0] <= current[1]) {
                // 更新當(dāng)前區(qū)間的終點(diǎn)
                current[1] = Math.max(current[1], interval[1]);
            } else {
                // 不重疊,添加新區(qū)間
                current = interval;
                merged.add(current);
            }
        }
        return merged.toArray(new int[merged.size()][]);
    }

22.1插入?yún)^(qū)間

    /**
     * 向已排序的區(qū)間數(shù)組中插入新區(qū)間,并合并重疊的區(qū)間
     *
     * @param intervals   已排序的區(qū)間數(shù)組,每個(gè)區(qū)間包含起始和結(jié)束位置
     * @param newInterval 需要插入的新區(qū)間
     * @return 插入并合并后的區(qū)間數(shù)組
     */
    public int[][] insert(int[][] intervals, int[] newInterval) {
        // 用于存儲(chǔ)最終結(jié)果
        List<int[]> result = new ArrayList<>();
        int i = 0;
        int n = intervals.length;

        // 添加所有在新區(qū)間之前的區(qū)間(不重疊的部分)
        while (i < n && intervals[i][1] < newInterval[0]) {
            result.add(intervals[i]);
            i++;
        }

        // 處理重疊區(qū)間:合并所有與新區(qū)間重疊的區(qū)間
        while (i < n && intervals[i][0] <= newInterval[1]) {
            // 更新新區(qū)間的起始位置為所有重疊區(qū)間中的最小起始位置
            newInterval[0] = Math.min(intervals[i][0], newInterval[0]);
            // 更新新區(qū)間的結(jié)束位置為所有重疊區(qū)間中的最大結(jié)束位置
            newInterval[1] = Math.max(intervals[i][1], newInterval[1]);
            i++;
        }
        // 添加合并后的新區(qū)間
        result.add(newInterval);

        // 添加所有在新區(qū)間之后的區(qū)間(不重疊的部分)
        while (i < n) {
            result.add(intervals[i]);
            i++;
        }

        // 將List轉(zhuǎn)換為二維數(shù)組并返回
        return result.toArray(new int[result.size()][]);
    }

23.接雨水
??? #動(dòng)態(tài)規(guī)劃 #木桶效應(yīng)建模 #分步線性遍歷

    public int trap(int[] height) {
        if (height == null || height.length == 0) {
            return 0;
        }
        int n = height.length;
        int[] leftMax = new int[n];
        int[] rightMax = new int[n];

        // 計(jì)算每個(gè)位置左邊的最大高度
        leftMax[0] = height[0];
        for (int i = 1; i < n; i++) {
            leftMax[i] = Math.max(leftMax[i - 1], height[i]);
        }

        // 計(jì)算每個(gè)位置右邊的最大高度
        rightMax[n - 1] = height[n - 1];
        for (int i = n - 2; i >= 0; i--) {
            rightMax[i] = Math.max(rightMax[i + 1], height[i]);
        }

        // 計(jì)算每個(gè)位置能接的雨水量
        int ans = 0;
        for (int i = 0; i < n; i++) {
            ans += Math.min(leftMax[i], rightMax[i]) - height[i];
        }

        return ans;
    }

24.環(huán)形鏈表 II
??? #快慢指針 #路徑對齊定位入口

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        if(head == null || head.next == null) {
            return null;
        }
        ListNode slow = head;
        ListNode fast = head;

        while(fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if(slow == fast) {
                ListNode ptr = head;
                while(ptr != slow) {
                    ptr = ptr.next;
                    slow = slow.next;
                }
                return ptr;
            }
        }
        return null;
    }
}

25.編輯距離
??? #動(dòng)態(tài)規(guī)劃

    /**
     * 計(jì)算兩個(gè)字符串之間的編輯距離(最少操作次數(shù))
     * 可以對字符串進(jìn)行的操作包括:插入、刪除、替換
     * 使用動(dòng)態(tài)規(guī)劃求解,dp[i][j]表示word1的前i個(gè)字符轉(zhuǎn)換到word2的前j個(gè)字符需要的最少操作數(shù)
     *
     * @param word1 源字符串
     * @param word2 目標(biāo)字符串
     * @return 最少操作次數(shù)
     */
    public int minDistance(String word1, String word2) {
        // 獲取兩個(gè)字符串的長度
        int m = word1.length();
        int n = word2.length();
        // 創(chuàng)建dp數(shù)組,dp[i][j]表示word1前i個(gè)字符轉(zhuǎn)換到word2前j個(gè)字符需要的最少操作數(shù)
        int[][] dp = new int[m + 1][n + 1];

        // 初始化邊界條件:空串轉(zhuǎn)換到另一個(gè)字符串的操作數(shù)
        for (int i = 0; i <= m; i++) {
            dp[i][0] = i;
        }
        for (int j = 0; j <= n; j++) {
            dp[0][j] = j;
        }

        // 動(dòng)態(tài)規(guī)劃計(jì)算最少操作數(shù)
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                // 當(dāng)前字符相同時(shí),不需要額外操作
                if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1];
                } else {
                    // 當(dāng)前字符不同時(shí),取替換、刪除、插入三種操作的最小值
                    dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i - 1][j], dp[i][j - 1])) + 1;
                }
            }
        }
        return dp[m][n];
    }

26.二叉樹中的最大路徑和
??? #遞歸分治

    /**
     * 計(jì)算二叉樹中的最大路徑和
     * 路徑被定義為從樹中的任意節(jié)點(diǎn)出發(fā),沿著樹的邊走到任意節(jié)點(diǎn)的序列
     * 路徑中至少包含一個(gè)節(jié)點(diǎn),且不一定經(jīng)過根節(jié)點(diǎn)
     *
     * @param root 二叉樹的根節(jié)點(diǎn)
     * @return 最大路徑和
     */
    public int maxPathSum(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int[] maxSum = {Integer.MIN_VALUE};
        maxGain(root, maxSum);
        return maxSum[0];
    }

    /**
     * 遞歸計(jì)算每個(gè)節(jié)點(diǎn)的最大貢獻(xiàn)值
     * 節(jié)點(diǎn)的最大貢獻(xiàn)值定義為:以該節(jié)點(diǎn)為起點(diǎn)的一條路徑,所能提供的最大路徑和
     *
     * @param node 當(dāng)前節(jié)點(diǎn)
     * @param maxSum 保存全局最大路徑和的數(shù)組
     * @return 以當(dāng)前節(jié)點(diǎn)為起點(diǎn)的最大貢獻(xiàn)值
     */
    private int maxGain(TreeNode node, int[] maxSum) {
        if (node == null) {
            return 0;
        }

        // 遞歸計(jì)算左右子節(jié)點(diǎn)的最大貢獻(xiàn)值,如果貢獻(xiàn)值為負(fù)則取0
        int leftGain = Math.max(maxGain(node.left, maxSum), 0);
        int rightGain = Math.max(maxGain(node.right, maxSum), 0);

        // 當(dāng)前節(jié)點(diǎn)的最大路徑和 = 當(dāng)前節(jié)點(diǎn)值 + 左子樹貢獻(xiàn) + 右子樹貢獻(xiàn)
        int priceNewPath = node.val + leftGain + rightGain;
        maxSum[0] = Math.max(maxSum[0], priceNewPath);

        // 返回節(jié)點(diǎn)的最大貢獻(xiàn)值,只能選擇左右子樹中的一條路徑
        return node.val + Math.max(leftGain, rightGain);
    }

27.刪除鏈表的倒數(shù)第 N 個(gè)結(jié)點(diǎn)
??? #快慢指針 #虛擬頭節(jié)點(diǎn)

    public ListNode removeNthFromEnd(ListNode head, int n) {
        if (head == null) {
            return null;
        }

        ListNode dummy = new ListNode(0, head);
        ListNode fast = head;
        ListNode slow = dummy;

        for (int i = 0; i < n; i++) {
            fast = fast.next;
        }

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

        slow.next = slow.next.next;
        return dummy.next;
    }
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {

        ListNode dummy = new ListNode(-1);
        ListNode pre = dummy;

        ListNode node = reverse(head);

        pre.next = node;
        int index = 0;
        while (pre != null) {
            index++;
            if (index == n) {
                pre.next = pre.next.next;
                break;
            } else {
                pre = pre.next;
            }
        }
        return reverse(dummy.next);
    }

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

28.尋找兩個(gè)正序數(shù)組的中位數(shù)
??? #雙指針

    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length, n = nums2.length;
        int len = m + n;
        int left = -1, right = -1;
        int aStart = 0, bStart = 0;
        
        // 遍歷到中位數(shù)位置
        for (int i = 0; i <= len/2; i++) {
            left = right;
            if (aStart < m && (bStart >= n || nums1[aStart] <= nums2[bStart])) {
                right = nums1[aStart++];
            } else {
                right = nums2[bStart++];
            }
        }
        
        // 如果總長度為奇數(shù),返回right;如果為偶數(shù),返回(left + right)/2
        return len % 2 == 0 ? (left + right) / 2.0 : right;
    }
class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {

        int m = nums1.length;
        int n = nums2.length;
        int[] nums = new int[m + n];

        int i = 0;
        int j = 0;

        int index = 0;
        while (i < m && j < n) {
            if (nums1[i] <= nums2[j]) {
                nums[index++] = nums1[i++];
            } else {
                nums[index++] = nums2[j++];
            }
        }

        while (i < m) {
            nums[index++] = nums1[i++];
        }

        while (j < n) {
            nums[index++] = nums2[j++];
        }

        if ((m + n) % 2 == 1) {
            return nums[(m + n) / 2];
        } else {
            return (nums[(m + n) / 2] + nums[(m + n) / 2 - 1]) / 2.0;
        }
    }
}

29.二叉樹的中序遍歷
??? #中序遍歷 #遞歸 #深度優(yōu)先搜索

    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<Integer>();
        inorder(root, result);
        return result;
    }

    private void inorder(TreeNode root, List<Integer> result) {
        if (root == null) {
            return;
        }
        inorder(root.left, result);
        result.add(root.val);
        inorder(root.right, result);
    }
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) {
            return result;
        }
        if (root.left != null) {
            result.addAll(inorderTraversal(root.left));
        }
        result.add(root.val);
        if (root.right != null) {
            result.addAll(inorderTraversal(root.right));
        }
        return result;
    }
}

30.排序鏈表
??? #快慢指針 #分治 #歸并 #虛擬頭節(jié)點(diǎn)

    public ListNode sortList(ListNode head) {

        if (head == null || head.next == null) {
            return head;
        }

        // 使用快慢指針找到中點(diǎn)
        ListNode slow = head;
        ListNode fast = head.next;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }

        // 分割鏈表
        ListNode mid = slow.next;
        slow.next = null;

        // 遞歸排序左右兩部分
        ListNode left = sortList(head);
        ListNode right = sortList(mid);

        // 合并兩個(gè)有序鏈表
        ListNode dummy = new ListNode(0);
        ListNode curr = dummy;

        while (left != null && right != null) {
            if (left.val <= right.val) {
                curr.next = left;
                left = left.next;
            } else {
                curr.next = right;
                right = right.next;
            }
            curr = curr.next;
        }

        curr.next = left != null ? left : right;

        return dummy.next;
    }

31.下一個(gè)排列
??? #雙指針 #貪心算法

    public void nextPermutation(int[] nums) {

        if (nums == null || nums.length == 1) {
            return;
        }

        int n = nums.length;

        // 從右到左,找到第一個(gè)升序位置i
        int i = n - 2;
        while (i >= 0) {
            if (nums[i] < nums[i + 1]) {
                break;
            }
            i--;
        }

        // 從右到左,找到第一個(gè)比 nums[i]大的數(shù)字的位置 j;交換兩者的位置
        if (i >= 0) {
            int j = n - 1;
            while (j > i) {
                if (nums[j] > nums[i]) {
                    swap(nums, i, j);
                    break;
                }
                j--;
            }
        }

        // 反轉(zhuǎn)i之后的數(shù)字
        reverse(nums, i + 1);
    }

    private void reverse(int[] nums, int i) {
        int left = i;
        int right = nums.length - 1;
        while (left < right) {
            swap(nums, left, right);
            left++;
            right--;
        }
    }

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

32.括號生成
??? #遞歸窮舉 #回溯

    /**
     * 生成所有可能的有效括號組合
     * @param n 括號對數(shù)
     * @return 所有有效的括號組合列表
     */
    public List<String> generateParenthesis(int n) {
        List<String> result = new ArrayList<>();
        backtrack(result, "", 0, 0, n);
        return result;
    }

    /**
     * 回溯法生成括號組合
     * @param result 存儲(chǔ)所有有效括號組合的列表
     * @param current 當(dāng)前生成的括號字符串
     * @param open 已使用的左括號數(shù)量
     * @param close 已使用的右括號數(shù)量
     * @param max 括號對數(shù)的最大值
     */
    private void backtrack(List<String> result, String current, int open, int close, int max) {
        // 當(dāng)前字符串長度等于最大長度時(shí),將其添加到結(jié)果集
        if (current.length() == max * 2) {
            result.add(current);
            return;
        }

        // 如果左括號數(shù)量小于最大值,可以添加左括號
        if (open < max) {
            backtrack(result, current + "(", open + 1, close, max);
        }
        // 如果右括號數(shù)量小于左括號數(shù)量,可以添加右括號
        if (close < open) {
            backtrack(result, current + ")", open, close + 1, max);
        }
    }

33.兩數(shù)相加
??? #虛擬頭節(jié)點(diǎn) #進(jìn)位狀態(tài)管理 #迭代法

    public ListNode addTwoNumbers(ListNode head1, ListNode head2) {
        // 創(chuàng)建虛擬頭節(jié)點(diǎn)
        ListNode dummy = new ListNode(0);
        ListNode curr = dummy;
        // 用于存儲(chǔ)進(jìn)位
        int carry = 0;

        // 當(dāng)兩個(gè)鏈表都未遍歷完或還有進(jìn)位時(shí)繼續(xù)循環(huán)
        while (head1 != null || head2 != null || carry != 0) {
            // 初始化本位和為進(jìn)位值
            int sum = carry;

            // 如果第一個(gè)鏈表未遍歷完,加上其值并移動(dòng)指針
            if (head1 != null) {
                sum += head1.val;
                head1 = head1.next;
            }

            // 如果第二個(gè)鏈表未遍歷完,加上其值并移動(dòng)指針
            if (head2 != null) {
                sum += head2.val;
                head2 = head2.next;
            }

            // 計(jì)算進(jìn)位和本位數(shù)
            carry = sum / 10;
            curr.next = new ListNode(sum % 10);
            curr = curr.next;
        }

        return dummy.next;
    }

34.滑動(dòng)窗口最大值

    public int[] maxSlidingWindow(int[] nums, int k) {
        // 特判
        if (nums == null || nums.length == 0) {
            return new int[0];
        }
        int n = nums.length;
        int[] result = new int[n - k + 1];

        // 雙端隊(duì)列存儲(chǔ)下標(biāo)
        Deque<Integer> deque = new LinkedList<>();
        for (int i = 0; i < n; i++) {
            // 1. 移除超出窗口的元素
            if (!deque.isEmpty() && deque.peekFirst() < i - k + 1) {
                deque.pollFirst();
            }

            // 2. 移除所有小于當(dāng)前元素的值
            while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {
                deque.pollLast();
            }

            // 3. 添加當(dāng)前元素
            deque.offerLast(i);

            // 4. 窗口形成后記錄結(jié)果
            if (i >= k - 1) {
                result[i - k + 1] = nums[deque.peekFirst()];
            }
        }
        return result;
    }

35.爬樓梯
??? #動(dòng)態(tài)規(guī)劃

    public int climbStairs(int n) {

        if (n < 1 || n > 45) {
            throw new IllegalArgumentException("入?yún)⒉徽_");
        }

        if (n == 1) {
            return 1;
        }

        if (n == 2) {
            return 2;
        }

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

        for (int i = 3; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
}

36.最長有效括號
??? #動(dòng)態(tài)規(guī)劃

    public int longestValidParentheses(String s) {
        int maxLen = 0;
        // left統(tǒng)計(jì)左括號數(shù)量,right統(tǒng)計(jì)右括號數(shù)量
        int left = 0, right = 0;
        
        // 從左向右掃描
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(') {
                left++;
            } else {
                right++;
            }
            
            // 當(dāng)左右括號數(shù)量相等時(shí),更新最大長度
            if (left == right) {
                maxLen = Math.max(maxLen, 2 * right);
            }
            // 當(dāng)右括號數(shù)量大于左括號時(shí),重置計(jì)數(shù)器
            if (right > left) {
                left = right = 0;
            }
        }
        
        // 從右向左再掃描一次
        left = right = 0;
        for (int i = s.length() - 1; i >= 0; i--) {
            if (s.charAt(i) == '(') {
                left++;
            } else {
                right++;
            }
            
            if (left == right) {
                maxLen = Math.max(maxLen, 2 * left);
            }
            // 當(dāng)左括號數(shù)量大于右括號時(shí),重置計(jì)數(shù)器
            if (left > right) {
                left = right = 0;
            }
        }
        
        return maxLen;
    }

37.零錢兌換
??? #動(dòng)態(tài)規(guī)劃

    /**
     * 計(jì)算湊成目標(biāo)金額所需的最少硬幣數(shù)量
     * 使用動(dòng)態(tài)規(guī)劃解決找零錢問題
     *
     * @param coins  可用的硬幣面值數(shù)組
     * @param amount 目標(biāo)金額
     * @return 所需的最少硬幣數(shù)量,如果無法湊出則返回-1
     */
    public int coinChange(int[] coins, int amount) {
        // 如果目標(biāo)金額為0,不需要硬幣
        if (amount == 0) {
            return 0;
        }

        // dp[i]表示湊成金額i所需的最少硬幣數(shù)
        int[] dp = new int[amount + 1];
        // 初始化dp數(shù)組,設(shè)置一個(gè)不可能達(dá)到的最大值
        for (int i = 1; i <= amount; i++) {
            dp[i] = amount + 1;
        }
        // 金額為0時(shí)不需要硬幣
        dp[0] = 0;

        // 計(jì)算每個(gè)金額所需的最少硬幣數(shù)
        for (int i = 1; i <= amount; i++) {
            // 嘗試每個(gè)硬幣面值
            for (int coin : coins) {
                // 當(dāng)前硬幣面值小于等于當(dāng)前計(jì)算的金額時(shí)
                if (coin <= i) {
                    // 更新dp[i],取當(dāng)前值和使用當(dāng)前硬幣后所需硬幣數(shù)+1的最小值
                    dp[i] = Math.min(dp[i], dp[i - coin] + 1);
                }
            }
        }

        // 如果dp[amount]大于amount,說明無法湊出目標(biāo)金額
        return dp[amount] > amount ? -1 : dp[amount];
    }

38.從前序與中序遍歷序列構(gòu)造二叉樹
??? #分治 #遞歸 #全局索引

    // 前序遍歷的索引
    private int preorderIndex = 0;

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return buildTreeHelper(preorder, inorder, 0, inorder.length - 1);
    }

    private TreeNode buildTreeHelper(int[] preorder, int[] inorder, int left, int right) {
        // 如果沒有節(jié)點(diǎn)要處理
        if (left > right) {
            return null;
        }

        // 創(chuàng)建當(dāng)前根節(jié)點(diǎn)
        int rootValue = preorder[preorderIndex++];
        TreeNode root = new TreeNode(rootValue);

        // 在中序遍歷中找到根節(jié)點(diǎn)的位置
        int rootPosition = findIndex(inorder, rootValue, left, right);

        // 先構(gòu)建左子樹,再構(gòu)建右子樹
        root.left = buildTreeHelper(preorder, inorder, left, rootPosition - 1);
        root.right = buildTreeHelper(preorder, inorder, rootPosition + 1, right);

        return root;
    }

    private int findIndex(int[] inorder, int target, int left, int right) {
        for (int i = left; i <= right; i++) {
            if (inorder[i] == target) {
                return i;
            }
        }
        return -1;
    }

39.最小棧
??? #鏈表模擬棧 #預(yù)存最小值 #動(dòng)態(tài)狀態(tài)傳遞

class MinStack {

    Node head;

    void push(int val) {
        if (head == null) {
            head = new Node(val, val);
        } else {
            Node newNode = new Node(val, Math.min(val, head.min));
            newNode.next = head;
            head = newNode;
        }
    }

    void pop() {
        if (head == null) {
            return;
        }
        head = head.next;
    }

    int top() {
        if (head == null) {
            return -1;
        }
        return head.val;
    }

    int getMin() {
        if (head == null) {
            return -1;
        }
        return head.min;
    }

    class Node {
        int val;
        int min;
        Node next;

        public Node(int val, int min) {
            this.val = val;
            this.min = min;
            this.next = null;
        }
    }

}

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(val);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.getMin();
 */

40.子集
??? #迭代法

    /**
     * 生成給定數(shù)組的所有可能子集
     * 使用迭代方法,對于數(shù)組中的每個(gè)數(shù)字,將其添加到已有的子集中形成新的子集
     *
     * @param nums 輸入的整數(shù)數(shù)組
     * @return 返回包含所有可能子集的列表
     */
    public List<List<Integer>> subsets(int[] nums) {
        // 創(chuàng)建結(jié)果列表,用于存儲(chǔ)所有子集
        List<List<Integer>> result = new ArrayList<>();
        // 添加空集作為初始子集
        result.add(new ArrayList<>());

        // 遍歷輸入數(shù)組中的每個(gè)數(shù)字
        for (int num : nums) {
            // 獲取當(dāng)前結(jié)果集的大小
            int size = result.size();
            // 遍歷現(xiàn)有的所有子集
            for (int i = 0; i < size; i++) {
                // 復(fù)制現(xiàn)有子集并添加當(dāng)前數(shù)字,形成新的子集
                List<Integer> subset = new ArrayList<>(result.get(i));
                subset.add(num);
                // 將新子集添加到結(jié)果集中
                result.add(subset);
            }
        }
        return result;
    }

41.最小覆蓋子串
??? #滑動(dòng)窗口 #雙指針 #貪心策略 #右擴(kuò)窗口、左縮優(yōu)化、計(jì)數(shù)器同步
暫時(shí)未看懂

    /**
     * 在字符串s中尋找包含字符串t中所有字符的最小子串
     * 使用滑動(dòng)窗口算法實(shí)現(xiàn)
     *
     * @param s 源字符串
     * @param t 目標(biāo)字符串
     * @return 包含t中所有字符的最小子串,如果不存在則返回空字符串
     */
    public String minWindow(String s, String t) {
        if (s == null || t == null || s.isEmpty() || t.isEmpty()) {
            return "";
        }

        // 記錄所需字符的頻率
        int[] freq = new int[128];
        for (char c : t.toCharArray()) {
            freq[c]++;
        }

        int start = 0, minLen = Integer.MAX_VALUE;
        int left = 0, count = t.length();

        // 滑動(dòng)窗口
        for (int right = 0; right < s.length(); right++) {
            // 更新窗口
            if (freq[s.charAt(right)]-- > 0) {
                count--;
            }

            // 找到可行解時(shí)收縮窗口
            while (count == 0) {
                // 更新最小子串
                if (right - left + 1 < minLen) {
                    start = left;
                    minLen = right - left + 1;
                }

                // 收縮左邊界
                if (++freq[s.charAt(left++)] > 0) {
                    count++;
                }
            }
        }

        return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen);
    }

42.對稱二叉樹
??? #遞歸 #深度優(yōu)先遍歷 #雙指針

    /**
     * 判斷一棵二叉樹是否是對稱的
     * 對稱二叉樹定義: 二叉樹的左右子樹鏡像對稱
     *
     * @param root 二叉樹的根節(jié)點(diǎn)
     * @return 如果二叉樹是對稱的返回true,否則返回false
     */
    public boolean isSymmetric(TreeNode root) {
        if (root == null) {
            return true;
        }
        return check(root.left, root.right);
    }

    /**
     * 遞歸檢查兩個(gè)子樹是否鏡像對稱
     *
     * @param left 左子樹節(jié)點(diǎn)
     * @param right 右子樹節(jié)點(diǎn)
     * @return 如果兩個(gè)子樹鏡像對稱返回true,否則返回false
     */
    private boolean check(TreeNode left, TreeNode right) {
        if (left == null && right == null) {
            return true;
        }
        if (left == null || right == null) {
            return false;
        }
        return left.val == right.val && check(left.left, right.right) && check(left.right, right.left);
    }

43.二叉樹的最大深度
??? #遞歸 #后序遍歷

    public int maxDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int leftDepth = maxDepth(root.left);
        int rightDepth = maxDepth(root.right);
        return Math.max(leftDepth, rightDepth) + 1;
    }

44.組合總和
??? #回溯選擇與撤銷 #剪枝減少無效計(jì)算 #順序約束去重

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        // 使用回溯算法解決組合總和問題
        List<List<Integer>> result = new ArrayList<>();
        List<Integer> current = new ArrayList<>();
        backtrack(candidates, target, 0, current, result);
        return result;
    }

    private void backtrack(int[] candidates, int target, int start, List<Integer> current, List<List<Integer>> result) {
        // 如果目標(biāo)值為0,說明當(dāng)前組合的和等于target,將其添加到結(jié)果中
        if (target == 0) {
            result.add(new ArrayList<>(current));
            return;
        }

        // 如果目標(biāo)值小于0,說明當(dāng)前組合的和超過了target,直接返回
        if (target < 0) {
            return;
        }

        // 從start開始遍歷candidates數(shù)組,避免重復(fù)組合
        for (int i = start; i < candidates.length; i++) {
            // 將當(dāng)前數(shù)字添加到組合中
            current.add(candidates[i]);
            // 遞歸調(diào)用,注意這里的start仍然是i,因?yàn)榭梢灾貜?fù)使用同一個(gè)數(shù)字
            backtrack(candidates, target - candidates[i], i, current, result);
            // 回溯,移除最后添加的數(shù)字
            current.remove(current.size() - 1);
        }
    }

45.最大正方形
??? #動(dòng)態(tài)規(guī)劃 #空間換時(shí)間優(yōu)化 #迭代法

    /**
     * 計(jì)算二維矩陣中最大正方形的面積
     * 使用動(dòng)態(tài)規(guī)劃的方法,dp[i][j]表示以matrix[i-1][j-1]為右下角的最大正方形邊長
     *
     * @param matrix 輸入的二維字符矩陣,包含'0'和'1'
     * @return 矩陣中由1組成的最大正方形面積
     */
    public int maximalSquare(char[][] matrix) {
        // 處理邊界情況
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return 0;
        }

        // 獲取矩陣的行數(shù)和列數(shù)
        int rows = matrix.length;
        int cols = matrix[0].length;
        // dp數(shù)組用于存儲(chǔ)以當(dāng)前位置為右下角的最大正方形邊長
        int[][] dp = new int[rows + 1][cols + 1];
        // 記錄最大正方形邊長
        int maxSide = 0;

        // 遍歷矩陣中的每個(gè)元素
        for (int i = 1; i <= rows; i++) {
            for (int j = 1; j <= cols; j++) {
                // 當(dāng)前位置為1時(shí),計(jì)算最大正方形邊長
                if (matrix[i - 1][j - 1] == '1') {
                    // 取左邊、上邊、左上角三個(gè)位置的最小值加1
                    dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
                    // 更新最大邊長
                    maxSide = Math.max(maxSide, dp[i][j]);
                }
            }
        }
        // 返回最大正方形的面積
        return maxSide * maxSide;
    }

46.旋轉(zhuǎn)圖像
??? #數(shù)學(xué)幾何變換 #原地交換

    public void rotate(int[][] matrix) {
        int n = matrix.length;
        // 水平翻轉(zhuǎn)
        for (int i = 0; i < n / 2; i++) {
            for (int j = 0; j < n; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[n - i - 1][j];
                matrix[n - i - 1][j] = temp;
            }
        }
        // 主對角線翻轉(zhuǎn)
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < i; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = temp;
            }
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容