LeetCode 题解

完整目录与书签版(修复版)
作者:MiniMax Agent | 版本:v4.0 | 日期:2025年10月

双指针 (Two Pointers)

1. 有序数组的Two Sum

问题描述: 在有序数组中找出两个数,使它们的和为target。

解题思路: 使用双指针,一个指针指向值较小的元素,一个指针指向值较大的元素。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。

复杂度分析

时间复杂度: O(N)

空间复杂度: O(1)

Java 代码实现

Java
public int[] twoSum(int[] numbers, int target) {
    if (numbers == null) return null;
    int i = 0, j = numbers.length - 1;
    while (i < j) {
        int sum = numbers[i] + numbers[j];
        if (sum == target) {
            return new int[]{i + 1, j + 1};
        } else if (sum < target) {
            i++;
        } else {
            j--;
        }
    }
    return null;
}
代码可水平滚动

排序 (Sorting)

1. Kth Element

问题描述: 找到数组中第k大的元素。

解题思路: 使用快速排序的划分思想,每次划分后确定一个元素的最终位置。

复杂度分析

时间复杂度: O(N)

空间复杂度: O(1)

Java 代码实现

Java
public int findKthLargest(int[] nums, int k) {
    if (nums == null || nums.length == 0) return -1;
    
    return findKthElement(nums, 0, nums.length - 1, nums.length - k);
}

private int findKthElement(int[] nums, int left, int right, int k) {
    if (left >= right) return nums[left];
    
    int pivotIndex = partition(nums, left, right);
    
    if (pivotIndex == k) {
        return nums[pivotIndex];
    } else if (pivotIndex < k) {
        return findKthElement(nums, pivotIndex + 1, right, k);
    } else {
        return findKthElement(nums, left, pivotIndex - 1, k);
    }
}

private int partition(int[] nums, int left, int right) {
    int pivot = nums[right];
    int i = left;
    
    for (int j = left; j < right; j++) {
        if (nums[j] <= pivot) {
            swap(nums, i, j);
            i++;
        }
    }
    
    swap(nums, i, right);
    return i;
}

private void swap(int[] nums, int i, int j) {
    int temp = nums[i];
    nums[i] = nums[j];
    nums[j] = temp;
}
代码可水平滚动

贪心思想 (Greedy)

1. 分配饼干

问题描述: 每个孩子都有一个满足度grid,每个饼干都有一个大小size,只有饼干的大小大于等于一个孩子的满足度,该孩子才会获得满足。求解最多可以获得满足的孩子数量。

解题思路: 给一个孩子的饼干应当尽量小并且又能满足该孩子,这样大饼干才能拿来给满足度比较大的孩子。因为满足度最小的孩子最容易得到满足,所以先满足满足度最小的孩子。

复杂度分析

时间复杂度: O(nlogn)

空间复杂度: O(1)

Java 代码实现

Java
public int findContentChildren(int[] grid, int[] size) {
    if (grid == null || size == null) return 0;
    Arrays.sort(grid);
    Arrays.sort(size);
    int gi = 0, si = 0;
    while (gi < grid.length && si < size.length) {
        if (grid[gi] <= size[si]) {
            gi++;
        }
        si++;
    }
    return gi;
}
代码可水平滚动

分治 (Divide and Conquer)

1. 不同的二叉搜索树

问题描述: 给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种。

解题思路: 使用递归的方式,假设以 i 为根节点,则左子树由 1...i-1 组成,右子树由 i+1...n 组成。

复杂度分析

时间复杂度: O(N³)

空间复杂度: O(N)

Java 代码实现

Java
public int numTrees(int n) {
    int[] dp = new int[n + 1];
    dp[0] = 1;
    dp[1] = 1;
    
    for (int i = 2; i <= n; i++) {
        for (int j = 1; j <= i; j++) {
            dp[i] += dp[j - 1] * dp[i - j];
        }
    }
    
    return dp[n];
}
代码可水平滚动

动态规划 (Dynamic Programming)

1. 爬楼梯

问题描述: 有N阶楼梯,每次可以上一阶或者两阶,求有多少种上楼梯的方法。

解题思路: 定义一个数组dp存储上楼梯的方法数,dp[i]表示走到第i个楼梯的方法数。

复杂度分析

时间复杂度: O(N)

空间复杂度: O(1)

Java 代码实现

Java
public int climbStairs(int n) {
    if (n <= 2) {
        return n;
    }
    int pre2 = 1, pre1 = 2;
    for (int i = 2; i < n; i++) {
        int cur = pre1 + pre2;
        pre2 = pre1;
        pre1 = cur;
    }
    return pre1;
}
代码可水平滚动

数学 (Math)

1. 生成素数序列

问题描述: 给定一个正整数 n,返回小于或等于 n 的所有素数。

解题思路: 使用埃拉托斯特尼筛选法,首先假设所有数字都是素数,然后依次标记非素数。

复杂度分析

时间复杂度: O(NloglogN)

空间复杂度: O(N)

Java 代码实现

Java
public int countPrimes(int n) {
    boolean[] isPrime = new boolean[n];
    for (int i = 2; i < n; i++) {
        isPrime[i] = true;
    }
    
    for (int i = 2; i * i < n; i++) {
        if (isPrime[i]) {
            for (int j = i * i; j < n; j += i) {
                isPrime[j] = false;
            }
        }
    }
    
    int count = 0;
    for (int i = 2; i < n; i++) {
        if (isPrime[i]) count++;
    }
    return count;
}
代码可水平滚动

链表 (Linked List)

1. 链表反转

问题描述: 反转链表。

解题思路: 使用头插法,每次将当前节点插入到新链表的头部。

复杂度分析

时间复杂度: O(N)

空间复杂度: O(1)

Java 代码实现

Java
public ListNode reverseList(ListNode head) {
    ListNode newHead = new ListNode(-1);
    while (head != null) {
        ListNode next = head.next;
        head.next = newHead.next;
        newHead.next = head;
        head = next;
    }
    return newHead.next;
}
代码可水平滚动

树 (Tree)

1. 树的高度

问题描述: 求二叉树的最大深度。

解题思路: 使用递归,树的深度等于左右子树深度的最大值加一。

复杂度分析

时间复杂度: O(N)

空间复杂度: O(H)

Java 代码实现

Java
public int maxDepth(TreeNode root) {
    if (root == null) return 0;
    return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
代码可水平滚动

栈和队列 (Stack and Queue)

1. 用栈实现队列

问题描述: 使用栈实现队列的 push 和 pop 操作。

解题思路: 使用两个栈,一个用于输入,一个用于输出。当输出栈为空时,将输入栈的所有元素弹出并压入输出栈。

复杂度分析

时间复杂度: O(1)

空间复杂度: O(N)

Java 代码实现

Java
class MyQueue {
    private Stack in = new Stack<>();
    private Stack out = new Stack<>();
    
    public void push(int x) {
        in.push(x);
    }
    
    public int pop() {
        if (out.isEmpty()) {
            while (!in.isEmpty()) {
                out.push(in.pop());
            }
        }
        return out.pop();
    }
    
    public int peek() {
        if (out.isEmpty()) {
            while (!in.isEmpty()) {
                out.push(in.pop());
            }
        }
        return out.peek();
    }
    
    public boolean empty() {
        return in.isEmpty() && out.isEmpty();
    }
}
代码可水平滚动

哈希表 (Hash Table)

1. 数组中两个数的和为给定值

问题描述: 在数组中找出两个数,它们的和为target。

解题思路: 使用哈希表记录已经遍历过的数字,对于当前数字,检查 target - nums[i] 是否在哈希表中。

复杂度分析

时间复杂度: O(N)

空间复杂度: O(N)

Java 代码实现

Java
public int[] twoSum(int[] nums, int target) {
    HashMap indexForNum = new HashMap<>();
    for (int i = 0; i < nums.length; i++) {
        if (indexForNum.containsKey(target - nums[i])) {
            return new int[]{indexForNum.get(target - nums[i]), i};
        } else {
            indexForNum.put(nums[i], i);
        }
    }
    return null;
}
代码可水平滚动

字符串 (String)

1. 字符串同构

问题描述: 判断两个字符串是否同构。

解题思路: 记录每个字符在字符串中上一次出现的位置,如果两个字符串中相同字符上次出现的位置相同,则它们是同构的。

复杂度分析

时间复杂度: O(N)

空间复杂度: O(1)

Java 代码实现

Java
public boolean isIsomorphic(String s, String t) {
    int[] preIndexOfS = new int[256];
    int[] preIndexOfT = new int[256];
    for (int i = 0; i < s.length(); i++) {
        char sc = s.charAt(i), tc = t.charAt(i);
        if (preIndexOfS[sc] != preIndexOfT[tc]) {
            return false;
        }
        preIndexOfS[sc] = i + 1;
        preIndexOfT[tc] = i + 1;
    }
    return true;
}
代码可水平滚动

数组与矩阵 (Array and Matrix)

1. 把数组中的0移到末尾

问题描述: 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

解题思路: 使用双指针,一个指针用于遍历数组,另一个指针指向当前应该放置非零元素的位置。

复杂度分析

时间复杂度: O(N)

空间复杂度: O(1)

Java 代码实现

Java
public void moveZeroes(int[] nums) {
    int index = 0;
    for (int i = 0; i < nums.length; i++) {
        if (nums[i] != 0) {
            nums[index++] = nums[i];
        }
    }
    while (index < nums.length) {
        nums[index++] = 0;
    }
}
代码可水平滚动

图 (Graph)

1. 判断是否为二分图

问题描述: 判断一个图是否为二分图。

解题思路: 使用BFS或DFS遍历图,为每个节点分配颜色,相邻节点必须分配不同的颜色。

复杂度分析

时间复杂度: O(V+E)

空间复杂度: O(V)

Java 代码实现

Java
public boolean isBipartite(int[][] graph) {
    int n = graph.length;
    int[] colors = new int[n];
    
    for (int i = 0; i < n; i++) {
        if (colors[i] == 0) {
            if (!isValidColor(graph, colors, i, 1)) {
                return false;
            }
        }
    }
    return true;
}

private boolean isValidColor(int[][] graph, int[] colors, int node, int color) {
    if (colors[node] != 0) {
        return colors[node] == color;
    }
    
    colors[node] = color;
    for (int neighbor : graph[node]) {
        if (!isValidColor(graph, colors, neighbor, -color)) {
            return false;
        }
    }
    return true;
}
代码可水平滚动

位运算 (Bit Manipulation)

1. 数组中唯一一个不重复的元素

问题描述: 找出数组中只出现一次的元素,其他元素都出现两次。

解题思路: 使用异或运算,相同数字异或结果为0,任何数字与0异或都等于它本身。

复杂度分析

时间复杂度: O(N)

空间复杂度: O(1)

Java 代码实现

Java
public int singleNumber(int[] nums) {
    int ret = 0;
    for (int n : nums) ret ^= n;
    return ret;
}
代码可水平滚动