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)
题目描述:给定两个字符串 s
和 t
,返回 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)
题目描述:给定一个二叉树和两个节点 p
和 q
,找到它们的最近公共祖先。
解题思路:递归法。从根节点开始,递归寻找两个节点的路径,找到分叉点。
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)
题目描述:根据一棵树的中序遍历和后序遍历的结果,重建这棵树。
解题思路:
- 后序遍历的最后一个元素是树的根节点。
- 在中序遍历中找到根节点的位置,左边是左子树,右边是右子树。
- 递归地重建左子树和右子树。
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 个排序链表,返回合并后的排序链表。
解题思路:
- 使用优先队列(最小堆)存储每个链表的当前节点。
- 每次从堆中取出最小的节点,加入结果链表,并将该节点的下一个节点加入堆中。
- 重复上述过程直到堆为空。
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)
题目描述:给定一个没有重复数字的序列,返回其所有可能的全排列。
解题思路:
- 使用回溯法,递归地生成所有可能的排列。
- 每次选择一个数字,将其加入当前排列,并从剩余数字中继续选择。
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)
题目描述:给定一个可包含重复数字的序列,返回其所有不重复的全排列。
解题思路:
- 使用回溯法,递归地生成所有可能的排列。
- 使用排序和跳过重复数字的方法避免重复排列。
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 度。
解题思路:
- 先转置矩阵(行变列,列变行)。
- 然后翻转每一行。
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)
题目描述:给定一个字符串数组,将字母异位词组合在一起。
解题思路:
- 使用哈希表,将每个字符串排序后的结果作为键,原字符串作为值。
- 遍历字符串数组,将每个字符串加入对应的键值对中。
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)
,即计算 x
的 n
次幂。
解题思路:
- 使用快速幂算法,通过递归或迭代实现。
- 处理负指数的情况。
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;
}
}
}
【推荐】博客园的心动:当一群程序员决定开源共建一个真诚相亲平台
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】Flutter适配HarmonyOS 5知识地图,实战解析+高频避坑指南
【推荐】凌霞软件回馈社区,携手博客园推出1Panel与Halo联合终身会员
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 提升Avalonia UI质感,跨平台图标库选型实践
· 突发,CSDN 崩了!程序员们开始慌了?
· C# 中委托和事件的深度剖析与应用场景
· 一个基于 .NET 8 + Ant Design Blazor 开发的简洁现代后台管理框架
· AppBox拖拽设计增删改查用户界面