LeetCode Top50 经典题目详解及 Java 代码实现

1. 两数之和(Two Sum)

题目描述:给定一个整数数组 nums 和一个目标值 target,请在该数组中找出和为目标值的两个整数,并返回他们的数组下标。

解题思路:使用哈希表存储数组元素及其索引,遍历数组时检查目标值与当前值的差是否已存在于哈希表中。

Java 代码实现

import java.util.HashMap;
import java.util.Map;

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

2. 三数之和(3Sum)

题目描述:给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a, b, c ,使得 a + b + c = 0。

解题思路:先对数组排序,然后使用双指针法,固定一个数后,用双指针在剩余部分查找和为零的两个数。

Java 代码实现

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

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

3. 最长回文子串(Longest Palindromic Substring)

题目描述:给定一个字符串 s,找到 s 中最长的回文子串。

解题思路:使用动态规划或中心扩展法。中心扩展法更简单,从每个字符及其两侧扩展,寻找最长回文。

Java 代码实现

public class Solution {
    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++) {
            int len1 = expandAroundCenter(s, i, i);
            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++;
        }
        return right - left - 1;
    }
}

4. 盛最多水的容器(Container With Most Water)

题目描述:给定一个长度为 n 的整数数组 height,有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i])。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

解题思路:使用双指针法,从两端开始向中间移动,移动较短的指针。

Java 代码实现

public class Solution {
    public int maxArea(int[] height) {
        int maxArea = 0;
        int left = 0, right = height.length - 1;
        while (left < right) {
            int width = right - left;
            int minHeight = Math.min(height[left], height[right]);
            maxArea = Math.max(maxArea, width * minHeight);
            if (height[left] < height[right]) {
                left++;
            } else {
                right--;
            }
        }
        return maxArea;
    }
}

5. 合并两个有序链表(Merge Two Sorted Lists)

题目描述:将两个升序链表合并为一个新的升序链表。

解题思路:递归或迭代法。迭代法更直观,使用一个哑节点简化操作。

Java 代码实现

public class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(0);
        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;
        }
        current.next = (l1 != null) ? l1 : l2;
        return dummy.next;
    }
}

6. 二叉树的后序遍历(Binary Tree Postorder Traversal)

题目描述:给定一个二叉树,返回其节点值的后序遍历。

解题思路:递归法或迭代法。迭代法使用栈模拟递归过程。

Java 代码实现

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) return result;
        Stack<TreeNode> stack = new Stack<>();
        TreeNode current = root;
        while (current != null || !stack.isEmpty()) {
            while (current != null) {
                stack.push(current);
                current = current.left;
            }
            current = stack.pop();
            result.add(current.val);
            current = current.right;
        }
        return result;
    }
}

7. 重建二叉树(Construct Binary Tree from Preorder and Inorder Traversal)

题目描述:根据一棵树的前序遍历与中序遍历重建这棵树。

解题思路:递归法。利用前序遍历的第一个元素为根节点,在中序遍历中找到根节点的位置,递归构建左、右子树。

Java 代码实现

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

    private TreeNode buildTreeHelper(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd) {
        if (preStart > preEnd) return null;
        TreeNode root = new TreeNode(preorder[preStart]);
        int inRootIndex = 0;
        for (int i = inStart; i <= inEnd; i++) {
            if (inorder[i] == root.val) {
                inRootIndex = i;
                break;
            }
        }
        int leftTreeSize = inRootIndex - inStart;
        root.left = buildTreeHelper(preorder, preStart + 1, preStart + leftTreeSize, inorder, inStart, inRootIndex - 1);
        root.right = buildTreeHelper(preorder, preStart + leftTreeSize + 1, preEnd, inorder, inRootIndex + 1, inEnd);
        return root;
    }
}

8. 用两个栈实现队列(Implement Queue using Stacks)

题目描述:用两个栈实现一个队列。

解题思路:一个栈用于入队,另一个栈用于出队。当需要出队时,将第一个栈
的元素压入第二个栈,然后弹出第二个栈的栈顶元素。

Java 代码实现

import java.util.Stack;

public class MyQueue {
    private Stack<Integer> stack1;
    private Stack<Integer> stack2;

    public MyQueue() {
        stack1 = new Stack<>();
        stack2 = new Stack<>();
    }

    public void push(int x) {
        stack1.push(x);
    }

    public int pop() {
        if (stack2.isEmpty()) {
            while (!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }

    public int peek() {
        if (stack2.isEmpty()) {
            while (!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
        }
        return stack2.peek();
    }

    public boolean empty() {
        return stack1.isEmpty() && stack2.isEmpty();
    }
}

9. 旋转数组(Rotate Array)

题目描述:将数组向右移动 k 步。

解题思路:三次反转法。先反转整个数组,再反转前 k 个元素,最后反转剩余部分。

Java 代码实现

public class Solution {
    public void rotate(int[] nums, int k) {
        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 temp = nums[start];
            nums[start] = nums[end];
            nums[end] = temp;
            start++;
            end--;
        }
    }
}

10. 最小路径和(Minimum Path Sum)

题目描述:给定一个 m×n 的网格,从左上角到右下角的最小路径和。

解题思路:动态规划。dp[i][j] 表示到达 (i, j) 的最小路径和。

Java 代码实现

public class Solution {
    public int minPathSum(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int[][] dp = new int[m][n];
        dp[0][0] = grid[0][0];
        for (int i = 1; i < m; i++) {
            dp[i][0] = dp[i - 1][0] + grid[i][0];
        }
        for (int j = 1; j < n; j++) {
            dp[0][j] = dp[0][j - 1] + grid[0][j];
        }
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
            }
        }
        return dp[m - 1][n - 1];
    }
}

11. N 皇后问题(N-Queens)

题目描述:在 n×n 的棋盘上放置 n 个皇后,使得它们互不攻击。

解题思路:回溯法。逐行放置皇后,检查当前行是否与之前的皇后冲突。

Java 代码实现

import java.util.ArrayList;
import java.util.List;

public class Solution {
    public List<List<String>> solveNQueens(int n) {
        List<List<String>> result = new ArrayList<>();
        char[][] board = new char[n][n];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                board[i][j] = '.';
            }
        }
        backtrack(result, board, 0);
        return result;
    }

    private void backtrack(List<List<String>> result, char[][] board, int row) {
        if (row == board.length) {
            result.add(construct(board));
            return;
        }
        for (int col = 0; col < board.length; col++) {
            if (isValid(board, row, col)) {
                board[row][col] = 'Q';
                backtrack(result, board, row + 1);
                board[row][col] = '.';
            }
        }
    }

    private boolean isValid(char[][] board, int row, int col) {
        for (int i = 0; i < row; i++) {
            if (board[i][col] == 'Q') return false;
        }
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
            if (board[i][j] == 'Q') return false;
        }
        for (int i = row - 1, j = col + 1; i >= 0 && j < board.length; i--, j++) {
            if (board[i][j] == 'Q') return false;
        }
        return true;
    }

    private List<String> construct(char[][] board) {
        List<String> res = new ArrayList<>();
        for (int i = 0; i < board.length; i++) {
            res.add(new String(board[i]));
        }
        return res;
    }
}

12. 最小覆盖子串(Minimum Window Substring)

题目描述:给定两个字符串 st,返回 s 中包含 t 所有字符的最小窗口。

解题思路:滑动窗口法。使用哈希表记录字符频率,维护窗口的有效性。

Java 代码实现

import java.util.HashMap;
import java.util.Map;

public class Solution {
    public String minWindow(String s, String t) {
        Map<Character, Integer> need = new HashMap<>();
        for (char c : t.toCharArray()) {
            need.put(c, need.getOrDefault(c, 0) + 1);
        }
        int left = 0, right = 0, valid = 0;
        Map<Character, Integer> window = new HashMap<>();
        int start = 0, len = Integer.MAX_VALUE;
        while (right < s.length()) {
            char c = s.charAt(right);
            right++;
            if (need.containsKey(c)) {
                window.put(c, window.getOrDefault(c, 0) + 1);
                if (window.get(c).equals(need.get(c))) {
                    valid++;
                }
            }
            while (valid == need.size()) {
                if (right - left < len) {
                    start = left;
                    len = right - left;
                }
                char d = s.charAt(left);
                left++;
                if (need.containsKey(d)) {
                    if (window.get(d).equals(need.get(d))) {
                        valid--;
                    }
                    window.put(d, window.get(d) - 1);
                }
            }
        }
        return len == Integer.MAX_VALUE ? "" : s.substring(start, start + len);
    }
}

13. 柱状图中最大的矩形(Largest Rectangle in Histogram)

题目描述:给定一个非负整数数组 heights,表示柱状图的高度,求柱状图中最大的矩形面积。

解题思路:单调栈。维护一个单调递增栈,计算每个柱子作为高度的最大矩形面积。

Java 代码实现

import java.util.Stack;

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

14. 二叉树的层序遍历(Binary Tree Level Order Traversal)

题目描述:给定一个二叉树,返回其节点值的层序遍历。

解题思路:使用队列实现层次遍历。

Java 代码实现

import java.util.ArrayList;
import java.util List;
import java.util.Queue;
import java.util.LinkedList;

public class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        if (root == null) return result;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            int levelSize = queue.size();
            List<Integer> level = new ArrayList<>();
            for (int i = 0; i < levelSize; i++) {
                TreeNode node = queue.poll();
                level.add(node.val);
                if (node.left != null) queue.offer(node.left);
                if(node.right != null) queue.offer(node.right);
            }
            result.add(level);
        }
        return result;
    }
}

15. 二叉树的最近公共祖先(Lowest Common Ancestor of a Binary Tree)

题目描述:给定一个二叉树和两个节点 pq,找到它们的最近公共祖先。

解题思路:递归法。从根节点开始,递归寻找两个节点的路径,找到分叉点。

Java 代码实现

public 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 && right != null) return root;
        return left != null ? left : right;
    }
}

16. 接雨水(Trapping Rain Water)

题目描述:给定一个非负整数数组 height,表示柱状图的高度,计算接雨水的容量。

解题思路:双指针法。从两端向中间移动,维护左右最大值,计算每个位置的雨水容量。

Java 代码实现

public class Solution {
    public int trap(int[] height) {
        int left = 0, right = height.length - 1;
        int leftMax = 0, rightMax = 0;
        int water = 0;
        while (left < right) {
            if (height[left] < height[right]) {
                if (height[left] >= leftMax) {
                    leftMax = height[left];
                } else {
                    water += leftMax - height[left];
                }
                left++;
            } else {
                if (height[right] >= rightMax) {
                    rightMax = height[right];
                } else {
                    water += rightMax - height[right];
                }
                right--;
            }
        }
        return water;
    }
}

17. 二叉树的最大深度(Maximum Depth of Binary Tree)

题目描述:给定一个二叉树,返回其最大深度。

解题思路:递归法。计算左、右子树的最大深度,取较大值加 1。

Java 代码实现

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

18. 二叉树的前序遍历(Binary Tree Preorder Traversal)

题目描述:给定一个二叉树,返回其节点值的前序遍历。

解题思路:递归法或迭代法。迭代法使用栈模拟递归过程。

Java 代码实现

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) return result;
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode node = stack.pop();
            result.add(node.val);
            if (node.right != null) stack.push(node.right);
            if (node.left != null) stack.push(node.left);
        }
        return result;
    }
}

19. 二叉树的中序遍历(Binary Tree Inorder Traversal)

题目描述:给定一个二叉树,返回其节点值的中序遍历。

解题思路:递归法或迭代法。迭代法使用栈模拟递归过程。

Java 代码实现

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) return result;
        Stack<TreeNode> stack = new Stack<>();
        TreeNode current = root;
        while (current != null || !stack.isEmpty()) {
            while (current != null) {
                stack.push(current);
                current = current.left;
            }
            current = stack.pop();
            result.add(current.val);
            current = current.right;
        }
        return result;
    }
}

20. 二叉树的后序遍历(Binary Tree Postorder Traversal)

题目描述:给定一个二叉树,返回其节点值的后序遍历。

解题思路:递归法或迭代法。迭代法使用栈模拟递归过程。

Java 代码实现

import java.util.ArrayList;
import java.util List;
import java.util.Stack;

public class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) return result;
        Stack<TreeNode> stack = new Stack<>();
        TreeNode current = root;
        while (current != null || !stack.isEmpty()) {
            while (current != null) {
                stack.push(current);
                result.add(0, current.val); // Add to the front for postorder
                current = current.right; // Reverse the order
            }
            current = stack.pop();
            current = current.left;
        }
        return result;
    }
}

21. 二叉树的层序遍历 II(Binary Tree Level Order Traversal II)

题目描述:给定一个二叉树,返回其节点值的层序遍历(自底向上)。

解题思路:使用队列实现层次遍历,然后反转结果。

Java 代码实现

import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.LinkedList;

public class Solution {
    public List<List<Integer>> levelOrderBottom(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        if (root == null) return result;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            int levelSize = queue.size();
            List<Integer> level = new ArrayList<>();
            for (int i = 0; i < levelSize; i++) {
                TreeNode node = queue.poll();
                level.add(node.val);
                if (node.left != null) queue.offer(node.left);
                if (node.right != null) queue.offer(node.right);
            }
            result.add(0, level); // Add to the front
        }
        return result;
    }
}

22. 二叉树的右视图(Binary Tree Right Side View)

题目描述:给定一个二叉树,返回其从右侧看到的节点值。

解题思路:使用队列实现层次遍历,每一层的最后一个节点即为右视图中的节点。

Java 代码实现

import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.LinkedList;

public class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) return result;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            int levelSize = queue.size();
            for (int i = 0; i < levelSize; i++) {
                TreeNode node = queue.poll();
                if (i == levelSize - 1) {
                    result.add(node.val);
                }
                if (node.left != null) queue.offer(node.left);
                if (node.right != null) queue.offer(node.right);
            }
        }
        return result;
    }
}

23. 二叉树的左视图(Binary Tree Left Side View)

题目描述:给定一个二叉树,返回其从左侧看到的节点值。

解题思路:使用队列实现层次遍历,每一层的第一个节点即为左视图中的节点。

Java 代码实现

import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.LinkedList;

public class Solution {
    public List<Integer> leftSideView(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) return result;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            int levelSize = queue.size();
            for (int i = 0; i < levelSize; i++) {
                TreeNode node = queue.poll();
                if (i == 0) {
                    result.add(node.val);
                }
                if (node.left != null) queue.offer(node.left);
                if (node.right != null) queue.offer(node.right);
            }
        }
        return result;
    }
}

24. 二叉树的镜像(Invert Binary Tree)

题目描述:给定一个二叉树,交换其所有左右子树。

解题思路:递归法。交换左右子树,递归处理左右子树。

Java 代码实现

public class Solution {
    public TreeNode invertTree(TreeNode root) {
        if (root == null) return null;
        TreeNode temp = root.left;
        root.left = invertTree(root.right);
        root.right = invertTree(temp);
        return root;
    }
}

25. 二叉树的直径(Diameter of Binary Tree)

题目描述:给定一个二叉树,返回其直径长度。

解题思路:递归法。计算每个节点的左、右子树的最大深度,更新直径。

Java 代码实现

public class Solution {
    private int diameter = 0;

    public int diameterOfBinaryTree(TreeNode root) {
        maxDepth(root);
        return diameter;
    }

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

26. 二叉树的最大路径和(Binary Tree Maximum Path Sum)

题目描述:给定一个二叉树,返回其最大路径和。

解题思路:递归法。计算每个节点的最大贡献值,更新全局最大路径和。

Java 代码实现

public class Solution {
    private int maxSum = Integer.MIN_VALUE;

    public int maxPathSum(TreeNode root) {
        maxGain(root);
        return maxSum;
    }

    private int maxGain(TreeNode node) {
        if (node == null) return 0;
        int leftGain = Math.max(maxGain(node.left), 0);
        int rightGain = Math.max(maxGain(node.right), 0);
        int priceNewpath = node.val + leftGain + rightGain;
        maxSum = Math.max(maxSum, priceNewpath);
        return node.val + Math.max(leftGain, rightGain);
    }
}

27. 二叉树的最小深度(Minimum Depth of Binary Tree)

题目描述:给定一个二叉树,返回其最小深度。

解题思路:递归法或层次遍历。层次遍历遇到第一个叶子节点时返回深度。

Java 代码实现

public class Solution {
    public int minDepth(TreeNode root) {
        if (root == null) return 0;
        if (root.left == null && root.right == null) return 1;
        int leftDepth = (root.left != null) ? minDepth(root.left) : Integer.MAX_VALUE;
        int rightDepth = (root.right != null) ? minDepth(root.right) : Integer.MAX_VALUE;
        return Math.min(leftDepth, rightDepth) + 1;
    }
}

28. 二叉树的平衡性(Balanced Binary Tree)

题目描述:给定一个二叉树,判断其是否为平衡二叉树。

解题思路:递归法。计算每个节点的左右子树深度差,判断是否平衡。

Java 代码实现

public class Solution {
    public boolean isBalanced(TreeNode root) {
        return dfsHeight(root) != -1;
    }

    private int dfsHeight(TreeNode node) {
        if (node == null) return 0;
        int leftHeight = dfsHeight(node.left);
        if (leftHeight == -1) return -1;
        int rightHeight = dfsHeight(node.right);
        if (rightHeight == -1) return -1;
        if (Math.abs(leftHeight - rightHeight) > 1) return -1;
        return Math.max(leftHeight, rightHeight) + 1;
    }
}

29. 二叉树的对称性(Symmetric Tree)

题目描述:给定一个二叉树,判断其是否为对称二叉树。

解题思路:递归法。比较左子树和右子树是否对称。

Java 代码实现

public class Solution {
    public boolean isSymmetric(TreeNode root) {
        if (root == null) return true;
        return isMirror(root.left, root.right);
    }

    private boolean isMirror(TreeNode left, TreeNode right) {
        if (left == null && right == null) return true;
        if (left == null || right == null) return false;
        return left.val == right.val && isMirror(left.left, right.right) && isMirror(left.right, right.left);
    }
}

30. 二叉树的序列化与反序列化(Serialize and Deserialize Binary Tree)

题目描述:设计一个算法序列化和反序列化二叉树。

解题思路:使用前序遍历序列化,使用队列反序列化。

Java 代码实现

import java.util.StringJoiner;

public class Codec {
    public String serialize(TreeNode root) {
        if (root == null) return "null";
        StringJoiner sj = new StringJoiner(",");
        serializeHelper(root, sj);
        return sj.toString();
    }

    private void serializeHelper(TreeNode node, StringJoiner sj) {
        if (node == null) {
            sj.add("null");
            return;
        }
        sj.add(String.valueOf(node.val));
        serializeHelper(node.left, sj);
        serializeHelper(node.right, sj);
    }

    public TreeNode deserialize(String data) {
        String[] nodes = data.split(",");
        return deserializeHelper(nodes, new int[]{0});
    }

    private TreeNode deserializeHelper(String[] nodes, int[] index) {
        if (nodes[index[0]].equals("null")) {
            index[0]++;
            return null;
        }
        TreeNode node = new TreeNode(Integer.parseInt(nodes[index[0]++]));
        node.left = deserializeHelper(nodes, index);
        node.right = deserializeHelper(nodes, index);
        return node;
    }
}

31. 二叉树的路径和(Path Sum)

题目描述:给定一个二叉树和一个目标值 sum,判断是否存在从根到叶子的路径,其路径和等于目标值。

解题思路:递归法。从根节点开始,递归检查路径和。

Java 代码实现

public class Solution {
    public boolean hasPathSum(TreeNode root, int sum) {
        if (root == null) return false;
        if (root.left == null && root.right == null) return root.val == sum;
        return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
    }
}

32. 二叉树的路径和 II(Path Sum II)

题目描述:给定一个二叉树和一个目标值 sum,返回所有从根到叶子的路径,其路径和等于目标值。

解题思路:递归法。从根节点开始,递归记录路径,检查路径和。

Java 代码实现

import java.util.ArrayList;
import java.util List;

public class Solution {
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        List<List<Integer>> result = new ArrayList<>();
        if (root == null) return result;
        List<Integer> path = new ArrayList<>();
        pathSumHelper(root, sum, path, result);
        return result;
    }

    private void pathSumHelper(TreeNode node, int sum, List<Integer> path, List<List<Integer>> result) {
        if (node == null) return;
        path.add(node.val);
        if (node.left == null && node.right == null && node.val == sum) {
            result.add(new ArrayList<>(path));
        }
        pathSumHelper(node.left, sum - node.val, path, result);
        pathSumHelper(node.right, sum - node.val, path, result);
        path.remove(path.size() - 1);
    }
}

33. 二叉树的路径和 III(Path Sum III)

题目描述:给定一个二叉树和一个目标值 sum,返回路径数量,路径和等于目标值。

解题思路:递归法。从每个节点开始,递归检查路径和。

Java 代码实现

public class Solution {
    public int pathSum(TreeNode root, int sum) {
        if (root == null) return 0;
        return pathSumFrom(root, sum) + pathSum(root.left, sum) + pathSum(root.right, sum);
    }

    private int pathSumFrom(TreeNode node, int sum) {
        if (node == null) return 0;
        int count = 0;
        if (node.val == sum) count++;
        count += pathSumFrom(node.left, sum - node.val);
        count += pathSumFrom(node.right, sum - node.val);
        return count;
    }
}

34. 二叉树的前序遍历与中序遍历重建(Construct Binary Tree from Preorder and Inorder Traversal)

题目描述:根据一棵树的前序遍历与中序遍历重建这棵树。

解题思路
递归法。利用前序遍历的第一个元素为根节点,在中序遍历中找到根节点的位置,递归构建左、右子树。

Java 代码实现

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

    private TreeNode buildTreeHelper(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd) {
        if (preStart > preEnd) return null;
        TreeNode root = new TreeNode(preorder[preStart]);
        int inRootIndex = 0;
        for (int i = inStart; i <= inEnd; i++) {
            if (inorder[i] == root.val) {
                inRootIndex = i;
                break;
            }
        }
        int leftTreeSize = inRootIndex - inStart;
        root.left = buildTreeHelper(preorder, preStart + 1, preStart + leftTreeSize, inorder, inStart, inRootIndex - 1);
        root.right = buildTreeHelper(preorder, preStart + leftTreeSize + 1, preEnd, inorder, inRootIndex + 1, inEnd);
        return root;
    }
}

35. 二叉树的中序遍历与后序遍历重建(Construct Binary Tree from Inorder and Postorder Traversal)

题目描述:根据一棵树的中序遍历与后序遍历重建这棵树。

解题思路:递归法。利用后序遍历的最后一个元素为根节点,在中序遍历中找到根节点的位置,递归构建左、右子树。

Java 代码实现

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

    private TreeNode buildTreeHelper(int[] inorder, int inStart, int inEnd, int[] postorder, int postStart, int postEnd) {
        if (postStart > postEnd) return null;
        TreeNode root = new TreeNode(postorder[postEnd]);
        int inRootIndex = 0;
        for (int i = inStart; i <= inEnd; i++) {
            if (inorder[i] == root.val) {
                inRootIndex = i;
                break;
            }
        }
        int rightTreeSize = inEnd - inRootIndex;
        root.left = buildTreeHelper(inorder, inStart, inRootIndex - 1, postorder, postStart, postEnd - rightTreeSize - 1);
        root.right = buildTreeHelper(inorder, inRootIndex + 1, inEnd, postorder, postEnd - rightTreeSize, postEnd - 1);
        return root;
    }
}

36. 二叉树的前序遍历与后序遍历重建(Construct Binary Tree from Preorder and Postorder Traversal)

题目描述:根据一棵树的前序遍历与后序遍历重建这棵树。

解题思路:递归法。利用前序遍历的第一个元素为根节点,在后序遍历中找到根节点的位置,递归构建左、右子树。

Java 代码实现

public class Solution {
    public TreeNode constructFromPrePost(int[] pre, int[] post) {
        return constructFromPrePostHelper(pre, 0, pre.length - 1, post, 0, post.length - 1);
    }

    private TreeNode constructFromPrePostHelper(int[] pre, int preStart, int preEnd, int[] post, int postStart, int postEnd) {
        if (preStart > preEnd) return null;
        TreeNode root = new TreeNode(pre[preStart]);
        if (preStart == preEnd) return root;
        int postIndex = postStart;
        while (post[postIndex] != pre[preStart + 1]) {
            postIndex++;
        }
        int leftTreeSize = postIndex - postStart + 1;
        root.left = constructFromPrePostHelper(pre, preStart + 1, preStart + leftTreeSize, post, postStart, postIndex);
        root.right = constructFromPrePostHelper(pre, preStart + leftTreeSize + 1, preEnd, post, postIndex + 1, postEnd - 1);
        return root;
    }
}

37. 二叉树的前序遍历与中序遍历重建(Construct Binary Tree from Preorder and Inorder Traversal)

题目描述:根据一棵树的前序遍历与中序遍历重建这棵树。

解题思路:递归法。利用前序遍历的第一个元素为根节点,在中序遍历中找到根节点的位置,递归构建左、右子树。

Java 代码实现

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

    private TreeNode buildTreeHelper(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd) {
        if (preStart > preEnd) return null;
        TreeNode root = new TreeNode(preorder[preStart]);
        int inRootIndex = 0;
        for (int i = inStart; i <= inEnd; i++) {
            if (inorder[i] == root.val) {
                inRootIndex = i;
                break;
            }
        }
        int leftTreeSize = inRootIndex - inStart;
        root.left = buildTreeHelper(preorder, preStart + 1, preStart + leftTreeSize, inorder, inStart, inRootIndex - 1);
        root.right = buildTreeHelper(preorder, preStart + leftTreeSize + 1, preEnd, inorder, inRootIndex + 1, inEnd);
        return root;
    }
}

38. 二叉树的中序遍历与后序遍历重建(Construct Binary Tree from Inorder and Postorder Traversal)

题目描述:根据一棵树的中序遍历与后序遍历重建这棵树。

解题思路:递归法。利用后序遍历的最后一个元素为根节点,在中序遍历中找到根节点的位置,递归构建左、右子树。

Java 代码实现

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

    private TreeNode buildTreeHelper(int[] inorder, int inStart, int inEnd, int[] postorder, int postStart, int postEnd) {
        if (postStart > postEnd) return null;
        TreeNode root = new TreeNode(postorder[postEnd]);
        int inRootIndex = 0;
        for (int i = inStart; i <= inEnd; i++) {
            if (inorder[i] == root.val) {
                inRootIndex = i;
                break;
            }
        }
        int rightTreeSize = inEnd - inRootIndex;
        root.left = buildTreeHelper(inorder, inStart, inRootIndex - 1, postorder, postStart, postEnd - rightTreeSize - 1);
        root.right = buildTreeHelper(inorder, inRootIndex + 1, inEnd, postorder, postEnd - rightTreeSize, postEnd - 1);
        return root;
    }
}

39. 二叉树的前序遍历与后序遍历重建(Construct Binary Tree from Preorder and Postorder Traversal)

题目描述:根据一棵树的前序遍历与后序遍历重建这棵树。

解题思路:递归法。利用前序遍历的第一个元素为根节点,在后序遍历中找到根节点的位置,递归构建左、右子树。

Java 代码实现

public class Solution {
    public TreeNode constructFromPrePost(int[] pre, int[] post) {
        return constructFromPrePostHelper(pre, 0, pre.length - 1, post, 0, post.length - 1);
    }

    private TreeNode constructFromPrePostHelper(int[] pre, int preStart, int preEnd, int[] post, int postStart, int postEnd) {
        if (preStart > preEnd) return null;
        TreeNode root = new TreeNode(pre[preStart]);
        if (preStart == preEnd) return root;
        int postIndex = postStart;
        while (post[postIndex] != pre[preStart + 1]) {
            postIndex++;
        }
        int leftTreeSize = postIndex - postStart + 1;
        root.left = constructFromPrePostHelper(pre, preStart + 1, pre
Start + leftTreeSize, post, postStart, postIndex);
        root.right = constructFromPrePostHelper(pre, preStart + leftTreeSize + 1, preEnd, post, postIndex + 1, postEnd - 1);
        return root;
    }
}

40. 二叉树的前序遍历与中序遍历重建(Construct Binary Tree from Preorder and Inorder Traversal)

题目描述:根据一棵树的前序遍历与中序遍历重建这棵树。

解题思路:递归法。利用前序遍历的第一个元素为根节点,在中序遍历中找到根节点的位置,递归构建左、右子树。

Java 代码实现

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

    private TreeNode buildTreeHelper(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd) {
        if (preStart > preEnd) return null;
        TreeNode root = new TreeNode(preorder[preStart]);
        int inRootIndex = 0;
        for (int i = inStart; i <= inEnd; i++) {
            if (inorder[i] == root.val) {
                inRootIndex = i;
                break;
            }
        }
        int leftTreeSize = inRootIndex - inStart;
        root.left = buildTreeHelper(preorder, preStart + 1, preStart + leftTreeSize, inorder, inStart, inRootIndex - 1);
        root.right = buildTreeHelper(preorder, preStart + leftTreeSize + 1, preEnd, inorder, inRootIndex + 1, inEnd);
        return root;
    }
}

41. 二叉树的中序遍历与后序遍历重建(Construct Binary Tree from Inorder and Postorder Traversal)

题目描述:根据一棵树的中序遍历与后序遍历重建这棵树。

解题思路:递归法。利用后序遍历的最后一个元素为根节点,在中序遍历中找到根节点的位置,递归构建左、右子树。

Java 代码实现

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

    private TreeNode buildTreeHelper(int[] inorder, int inStart, int inEnd, int[] postorder, int postStart, int postEnd) {
        if (postStart > postEnd) return null;
        TreeNode root = new TreeNode(postorder[postEnd]);
        int inRootIndex = 0;
        for (int i = inStart; i <= inEnd; i++) {
            if (inorder[i] == root.val) {
                inRootIndex = i;
                break;
            }
        }
        int rightTreeSize = inEnd - inRootIndex;
        root.left = buildTreeHelper(inorder, inStart, inRootIndex - 1, postorder, postStart, postEnd - rightTreeSize - 1);
        root.right = buildTreeHelper(inorder, inRootIndex + 1, inEnd, postorder, postEnd - rightTreeSize, postEnd - 1);
        return root;
    }
}

42. 二叉树的前序遍历与后序遍历重建(Construct Binary Tree from Preorder and Postorder Traversal)

题目描述:根据一棵树的前序遍历与后序遍历重建这棵树。

解题思路:递归法。利用前序遍历的第一个元素为根节点,在后序遍历中找到根节点的位置,递归构建左、右子树。

Java 代码实现

public class Solution {
    public TreeNode constructFromPrePost(int[] pre, int[] post) {
        return constructFromPrePostHelper(pre, 0, pre.length - 1, post, 0, post.length - 1);
    }

    private TreeNode constructFromPrePostHelper(int[] pre, int preStart, int preEnd, int[] post, int postStart, int postEnd) {
        if (preStart > preEnd) return null;
        TreeNode root = new TreeNode(pre[preStart]);
        if (preStart == preEnd) return root;
        int postIndex = postStart;
        while (post[postIndex] != pre[preStart + 1]) {
            postIndex++;
        }
        int leftTreeSize = postIndex - postStart + 1;
        root.left = constructFromPrePostHelper(pre, preStart + 1, preStart + leftTreeSize, post, postStart, postIndex);
        root.right = constructFromPrePostHelper(pre, preStart + leftTreeSize + 1, preEnd, post, postIndex + 1, postEnd - 1);
        return root;
    }
}

43. 二叉树的前序遍历与中序遍历重建(Construct Binary Tree from Preorder and Inorder Traversal)

题目描述:根据一棵树的前序遍历与中序遍历重建这棵树。

解题思路:递归法。利用前序遍历的第一个元素为根节点,在中序遍历中找到根节点的位置,递归构建左、右子树。

Java 代码实现

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

    private TreeNode buildTreeHelper(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd) {
        if (preStart > preEnd) return null;
        TreeNode root = new TreeNode(preorder[preStart]);
        int inRootIndex = 0;
        for (int i = inStart; i <= inEnd; i++) {
            if (inorder[i] == root.val) {
                inRootIndex = i;
                break;
            }
        }
        int leftTreeSize = inRootIndex - inStart;
        root.left = buildTreeHelper(preorder, preStart + 1, preStart + leftTreeSize, inorder, inStart, inRootIndex - 1);
        root.right = buildTreeHelper(preorder, preStart + leftTreeSize + 1, preEnd, inorder, inRootIndex + 1, inEnd);
        return root;
    }
}

44. 二叉树的中序遍历与后序遍历重建(Construct Binary Tree from Inorder and Postorder Traversal)

题目描述:根据一棵树的中序遍历和后序遍历的结果,重建这棵树。

解题思路

  1. 后序遍历的最后一个元素是树的根节点。
  2. 在中序遍历中找到根节点的位置,左边是左子树,右边是右子树。
  3. 递归地重建左子树和右子树。

Java 代码实现

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

    private TreeNode buildTreeHelper(int[] inorder, int inStart, int inEnd, int[] postorder, int postStart, int postEnd) {
        if (postStart > postEnd) return null;
        TreeNode root = new TreeNode(postorder[postEnd]);
        int inRootIndex = 0;
        for (int i = inStart; i <= inEnd; i++) {
            if (inorder[i] == root.val) {
                inRootIndex = i;
                break;
            }
        }
        int rightTreeSize = inEnd - inRootIndex;
        root.left = buildTreeHelper(inorder, inStart, inRootIndex - 1, postorder, postStart, postEnd - rightTreeSize - 1);
        root.right = buildTreeHelper(inorder, inRootIndex + 1, inEnd, postorder, postEnd - rightTreeSize, postEnd - 1);
        return root;
    }
}

45. 合并K个有序链表(Merge k Sorted Lists)

题目描述:合并 k 个排序链表,返回合并后的排序链表。

解题思路

  1. 使用优先队列(最小堆)存储每个链表的当前节点。
  2. 每次从堆中取出最小的节点,加入结果链表,并将该节点的下一个节点加入堆中。
  3. 重复上述过程直到堆为空。

Java 代码实现

import java.util.PriorityQueue;

public class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        PriorityQueue<ListNode> queue = new PriorityQueue<>((a, b) -> a.val - b.val);
        for (ListNode list : lists) {
            if (list != null) {
                queue.add(list);
            }
        }
        ListNode dummy = new ListNode(0);
        ListNode current = dummy;
        while (!queue.isEmpty()) {
            ListNode node = queue.poll();
            current.next = node;
            current = current.next;
            if (node.next != null) {
                queue.add(node.next);
            }
        }
        return dummy.next;
    }
}

46. 全排列(Permutations)

题目描述:给定一个没有重复数字的序列,返回其所有可能的全排列。

解题思路

  1. 使用回溯法,递归地生成所有可能的排列。
  2. 每次选择一个数字,将其加入当前排列,并从剩余数字中继续选择。

Java 代码实现

import java.util.ArrayList;
import java.util.List;

public class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        backtrack(result, new ArrayList<>(), nums);
        return result;
    }

    private void backtrack(List<List<Integer>> result, List<Integer> tempList, int[] nums) {
        if (tempList.size() == nums.length) {
            result.add(new ArrayList<>(tempList));
        } else {
            for (int i = 0; i < nums.length; i++) {
                if (tempList.contains(nums[i])) continue; // 跳过已选择的数字
                tempList.add(nums[i]);
                backtrack(result, tempList, nums);
                tempList.remove(tempList.size() - 1);
            }
        }
    }
}

47. 全排列 II(Permutations II)

题目描述:给定一个可包含重复数字的序列,返回其所有不重复的全排列。

解题思路

  1. 使用回溯法,递归地生成所有可能的排列。
  2. 使用排序和跳过重复数字的方法避免重复排列。

Java 代码实现

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(nums); // 排序以跳过重复数字
        backtrack(result, new ArrayList<>(), nums, new boolean[nums.length]);
        return result;
    }

    private void backtrack(List<List<Integer>> result, List<Integer> tempList, int[] nums, boolean[] used) {
        if (tempList.size() == nums.length) {
            result.add(new ArrayList<>(tempList));
        } else {
            for (int i = 0; i < nums.length; i++) {
                if (used[i] || (i > 0 && nums[i] == nums[i - 1] && !used[i - 1])) continue;
                used[i] = true;
                tempList.add(nums[i]);
                backtrack(result, tempList, nums, used);
                used[i] = false;
                tempList.remove(tempList.size() - 1);
            }
        }
    }
}

48. 旋转图像(Rotate Image)

题目描述:给定一个 n×n 的二维矩阵,将矩阵顺时针旋转 90 度。

解题思路

  1. 先转置矩阵(行变列,列变行)。
  2. 然后翻转每一行。

Java 代码实现

public class Solution {
    public void rotate(int[][] matrix) {
        int n = matrix.length;
        // 转置矩阵
        for (int i = 0; i < n; i++) {
            for (int j = i; j < n; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = temp;
            }
        }
        // 翻转每一行
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n / 2; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[i][n - 1 - j];
                matrix[i][n - 1 - j] = temp;
            }
        }
    }
}

49. 字母异位词分组(Group Anagrams)

题目描述:给定一个字符串数组,将字母异位词组合在一起。

解题思路

  1. 使用哈希表,将每个字符串排序后的结果作为键,原字符串作为值。
  2. 遍历字符串数组,将每个字符串加入对应的键值对中。

Java 代码实现

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        Map<String, List<String>> map = new HashMap<>();
        for (String str : strs) {
            char[] chars = str.toCharArray();
            Arrays.sort(chars);
            String sortedStr = new String(chars);
            if (!map.containsKey(sortedStr)) {
                map.put(sortedStr, new ArrayList<>());
            }
            map.get(sortedStr).add(str);
        }
        return new ArrayList<>(map.values());
    }
}

50. Pow(x, n)(Pow(x, n))

题目描述:实现 pow(x, n),即计算 xn 次幂。

解题思路

  1. 使用快速幂算法,通过递归或迭代实现。
  2. 处理负指数的情况。

Java 代码实现

public class Solution {
    public double myPow(double x, int n) {
        long N = n;
        if (N < 0) {
            x = 1 / x;
            N = -N;
        }
        return fastPow(x, N);
    }

    private double fastPow(double x, long n) {
        if (n == 0) return 1;
        double half = fastPow(x, n / 2);
        if (n % 2 == 0) {
            return half * half;
        } else {
            return half * half * x;
        }
    }
}
posted @ 2025-04-16 11:48  软件职业规划  阅读(3)  评论(0)    收藏  举报
相关博文:
阅读排行:
· 提升Avalonia UI质感,跨平台图标库选型实践
· 突发,CSDN 崩了!程序员们开始慌了?
· C# 中委托和事件的深度剖析与应用场景
· 一个基于 .NET 8 + Ant Design Blazor 开发的简洁现代后台管理框架
· AppBox拖拽设计增删改查用户界面
点击右上角即可分享
微信分享提示