跳转至

LeetCode 100+ 题详解 - 完整刷题指南

重要性:⭐⭐⭐⭐⭐ 学习时间:2-3个月 目标:大厂面试准备 题目数量:100+道


📚 目录

  1. 数组(20题)
  2. 链表(15题)
  3. 树(20题)
  4. 动态规划(20题)
  5. 图(10题)
  6. 排序/搜索(15题)

数组(20题)

题目1:两数之和(Two Sum)⭐⭐⭐⭐⭐

题目链接LeetCode 1

难度:简单

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

示例

Text Only
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。


解法1:暴力法

思路:双重循环,枚举所有可能的两数组合

Python
def two_sum_brute(nums, target):
    """
    两数之和(暴力法)
    时间:O(n²)
    空间:O(1)
    """
    n = len(nums)
    for i in range(n):
        for j in range(i + 1, n):
            if nums[i] + nums[j] == target:
                return [i, j]
    return []

复杂度分析: - 时间:O(n²),双重循环 - 空间:O(1),不需要额外空间


解法2:哈希表(推荐)⭐

思路:用哈希表存储已访问的数字及其索引

Python
def two_sum_hash(nums, target):
    """
    两数之和(哈希表)
    时间:O(n)
    空间:O(n)
    """
    # 创建哈希表:数字 → 索引
    num_to_index = {}

    for i, num in enumerate(nums):
        # 计算需要的补数
        complement = target - num

        # 检查补数是否已在哈希表中
        if complement in num_to_index:
            return [num_to_index[complement], i]

        # 将当前数字存入哈希表
        num_to_index[num] = i

    return []

执行过程演示

Text Only
输入:nums = [2,7,11,15], target = 9

第1次迭代 (i=0, num=2):
  - complement = 9 - 2 = 7
  - 7 不在哈希表中
  - 存储:{2: 0}

第2次迭代 (i=1, num=7):
  - complement = 9 - 7 = 2
  - 2 在哈希表中!索引为 0
  - 返回 [0, 1] ✓

结果:[0, 1]

复杂度分析: - 时间:O(n),单次遍历 - 空间:O(n),哈希表最多存储n个元素


解法3:双指针(需排序)

思路:先排序,再用双指针从两端向中间查找

Python
def two_sum_two_pointers(nums, target):
    """
    两数之和(双指针,需排序)
    时间:O(n log n)
    空间:O(n)
    """
    # 创建带索引的数组
    nums_with_index = [(num, i) for i, num in enumerate(nums)]  # enumerate同时获取索引和值

    # 排序
    nums_with_index.sort()

    # 双指针
    left, right = 0, len(nums) - 1
    while left < right:
        current_sum = nums_with_index[left][0] + nums_with_index[right][0]

        if current_sum == target:
            return [nums_with_index[left][1], nums_with_index[right][1]]
        elif current_sum < target:
            left += 1
        else:
            right -= 1

    return []

复杂度分析: - 时间:O(n log n),主要是排序 - 空间:O(n),存储带索引的数组


题目2:买卖股票的最佳时机(Best Time to Buy and Sell Stock)⭐⭐⭐⭐⭐

题目链接LeetCode 121

难度:简单

问题描述: 给定一个数组 prices,它的第 i 个元素 prices[i] 是一支给定股票第 i 天的价格。如果你最多只允许完成一笔交易(即买入和卖出一只股票),设计一个算法来计算你所能获取的最大利润。

示例

Text Only
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。


解法1:暴力法

Python
def max_profit_brute(prices):
    """
    买卖股票(暴力法)
    时间:O(n²)
    空间:O(1)
    """
    max_profit = 0
    n = len(prices)

    for i in range(n):
        for j in range(i + 1, n):
            profit = prices[j] - prices[i]
            max_profit = max(max_profit, profit)

    return max_profit

解法2:一次遍历(推荐)⭐

思路:记录最低价格,每次计算当前价格卖出能获得的利润

Python
def max_profit(prices):
    """
    买卖股票(一次遍历)
    时间:O(n)
    空间:O(1)
    """
    if not prices:
        return 0

    min_price = prices[0]  # 最低价格
    max_profit = 0         # 最大利润

    for price in prices[1:]:
        # 更新最低价格
        min_price = min(min_price, price)

        # 更新最大利润
        profit = price - min_price
        max_profit = max(max_profit, profit)

    return max_profit

执行过程演示

Text Only
输入:prices = [7,1,5,3,6,4]

第1天 (price=7):
  - min_price = 7
  - profit = 7 - 7 = 0
  - max_profit = 0

第2天 (price=1):
  - min_price = min(7, 1) = 1
  - profit = 1 - 1 = 0
  - max_profit = 0

第3天 (price=5):
  - min_price = 1
  - profit = 5 - 1 = 4
  - max_profit = 4

第4天 (price=3):
  - min_price = 1
  - profit = 3 - 1 = 2
  - max_profit = 4

第5天 (price=6):
  - min_price = 1
  - profit = 6 - 1 = 5
  - max_profit = 5 ← 最大利润

第6天 (price=4):
  - min_price = 1
  - profit = 4 - 1 = 3
  - max_profit = 5

结果:5

核心思想: - 保持"在最低点买入"的策略 - 每天都计算"如果今天卖出"能赚多少 - 取最大值


题目3:最大子数组和(Maximum Subarray)⭐⭐⭐⭐⭐

题目链接LeetCode 53

难度:中等

问题描述: 给定一个整数数组 nums,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例

Text Only
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。


解法1:Kadane算法(推荐)⭐

核心思想:动态规划,dp[i] = max(nums[i], dp[i-1] + nums[i])

Python
def max_sub_array(nums):
    """
    最大子数组和(Kadane算法)
    时间:O(n)
    空间:O(1)
    """
    if not nums:
        return 0

    # 当前子数组和
    current_sum = nums[0]
    # 最大子数组和
    max_sum = nums[0]

    for num in nums[1:]:
        # 选择:扩展当前子数组 vs 从当前数字重新开始
        current_sum = max(num, current_sum + num)

        # 更新最大值
        max_sum = max(max_sum, current_sum)

    return max_sum

执行过程演示

Text Only
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]

初始化:
  - current_sum = -2
  - max_sum = -2

第2个元素 (num=1):
  - current_sum = max(1, -2+1) = max(1, -1) = 1
  - max_sum = max(-2, 1) = 1

第3个元素 (num=-3):
  - current_sum = max(-3, 1-3) = max(-3, -2) = -2
  - max_sum = max(1, -2) = 1

第4个元素 (num=4):
  - current_sum = max(4, -2+4) = max(4, 2) = 4  ← 重新开始
  - max_sum = max(1, 4) = 4

第5个元素 (num=-1):
  - current_sum = max(-1, 4-1) = max(-1, 3) = 3
  - max_sum = max(4, 3) = 4

第6个元素 (num=2):
  - current_sum = max(2, 3+2) = max(2, 5) = 5
  - max_sum = max(4, 5) = 5

第7个元素 (num=1):
  - current_sum = max(1, 5+1) = max(1, 6) = 6
  - max_sum = max(5, 6) = 6  ← 最大值

第8个元素 (num=-5):
  - current_sum = max(-5, 6-5) = max(-5, 1) = 1
  - max_sum = max(6, 1) = 6

第9个元素 (num=4):
  - current_sum = max(4, 1+4) = max(4, 5) = 5
  - max_sum = max(6, 5) = 6

结果:6
子数组:[4, -1, 2, 1]

核心思想: - 遍历数组,维护两个变量 - current_sum:以当前元素结尾的最大子数组和 - max_sum:全局最大子数组和 - 对于每个元素,决定是"继续前面的子数组"还是"从这里重新开始"


解法2:分治法

Python
def max_sub_array_divide(nums):
    """
    最大子数组和(分治法)
    时间:O(n log n)
    空间:O(log n)
    """
    def divide_conquer(left, right):
        if left == right:
            return nums[left]

        mid = (left + right) // 2

        # 左半部分的最大子数组和
        left_max = divide_conquer(left, mid)

        # 右半部分的最大子数组和
        right_max = divide_conquer(mid + 1, right)

        # 跨越中点的最大子数组和
        # 从中点向左扩展
        left_sum = float('-inf')
        current_sum = 0
        for i in range(mid, left - 1, -1):
            current_sum += nums[i]
            left_sum = max(left_sum, current_sum)

        # 从中点+1向右扩展
        right_sum = float('-inf')
        current_sum = 0
        for i in range(mid + 1, right + 1):
            current_sum += nums[i]
            right_sum = max(right_sum, current_sum)

        cross_max = left_sum + right_sum

        # 返回三者中的最大值
        return max(left_max, right_max, cross_max)

    if not nums:
        return 0

    return divide_conquer(0, len(nums) - 1)

题目4:删除有序数组中的重复项(Remove Duplicates from Sorted Array)⭐⭐⭐

题目链接LeetCode 26

难度:简单

问题描述: 给你一个有序数组 nums,请你原地删除重复的元素,使每个元素只出现一次,返回删除后数组的新长度。

示例

Text Only
输入:nums = [1,1,2]
输出:2, nums = [1,2]
解释:函数应该返回新的长度 2,并且原数组 nums 的前两个元素被修改为 1, 2 。


解法:双指针(推荐)⭐

思路:慢指针指向不重复的位置,快指针遍历数组

Python
def remove_duplicates(nums):
    """
    删除有序数组中的重复项(双指针)
    时间:O(n)
    空间:O(1)
    """
    if not nums:
        return 0

    # 慢指针:指向不重复的最后位置
    slow = 0

    # 快指针:遍历数组
    for fast in range(1, len(nums)):
        # 当快指针指向的元素与慢指针不同时
        if nums[fast] != nums[slow]:
            # 慢指针前进
            slow += 1
            # 复制新元素
            nums[slow] = nums[fast]

    # 返回长度(索引+1)
    return slow + 1

执行过程演示

Text Only
输入:nums = [1,1,2]

初始状态:
  - slow = 0, fast = 1
  - nums = [1,1,2]

第1次迭代 (fast=1):
  - nums[1]=1, nums[0]=1
  - 相等,不操作

第2次迭代 (fast=2):
  - nums[2]=2, nums[0]=1
  - 不相等!
  - slow += 1 → slow = 1
  - nums[1] = nums[2] → nums = [1,2,2]

结果:
  - 返回 2 (slow+1)
  - nums = [1,2,2]
  - 前2个元素:[1,2] ✓


题目5:轮转数组(Rotate Array)⭐⭐⭐⭐

题目链接LeetCode 189

难度:中等

问题描述: 给定一个数组,将数组中的元素向右移动 k 个位置。

示例

Text Only
输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右旋转 1 步: [7,1,2,3,4,5,6]
向右旋转 2 步: [6,7,1,2,3,4,5]
向右旋转 3 步: [5,6,7,1,2,3,4]


解法1:三次翻转(推荐)⭐

思路: 1. 翻转整个数组 2. 翻转前k个元素 3. 翻转后n-k个元素

Python
def rotate(nums, k):
    """
    轮转数组(三次翻转)
    时间:O(n)
    空间:O(1)
    """
    n = len(nums)
    k %= n  # 处理 k >= n 的情况

    def reverse(left, right):
        """翻转 nums[left:right+1]"""
        while left < right:
            nums[left], nums[right] = nums[right], nums[left]
            left += 1
            right -= 1

    # 三次翻转
    reverse(0, n - 1)      # 翻转整个数组
    reverse(0, k - 1)      # 翻转前k个元素
    reverse(k, n - 1)      # 翻转后n-k个元素

执行过程演示

Text Only
输入:nums = [1,2,3,4,5,6,7], k = 3

初始数组:[1,2,3,4,5,6,7]

第1步:翻转整个数组 [0,6]
  [1,2,3,4,5,6,7] → [7,6,5,4,3,2,1]

第2步:翻转前3个元素 [0,2]
  [7,6,5,4,3,2,1] → [5,6,7,4,3,2,1]

第3步:翻转后4个元素 [3,6]
  [5,6,7,4,3,2,1] → [5,6,7,1,2,3,4]

结果:[5,6,7,1,2,3,4] ✓


解法2:使用额外数组

Python
def rotate_extra_array(nums, k):
    """
    轮转数组(额外数组)
    时间:O(n)
    空间:O(n)
    """
    n = len(nums)
    k %= n

    # 创建新数组
    result = [0] * n

    for i in range(n):
        result[(i + k) % n] = nums[i]

    # 复制回原数组
    for i in range(n):
        nums[i] = result[i]

题目6:除自身以外数组的乘积(Product of Array Except Self)⭐⭐⭐⭐

题目链接LeetCode 238

难度:中等

问题描述: 给定一个整数数组 nums,返回数组 answer,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。

示例

Text Only
输入:nums = [1,2,3,4]
输出:[24,12,8,6]
解释:
- answer[0] = 2*3*4 = 24
- answer[1] = 1*3*4 = 12
- answer[2] = 1*2*4 = 8
- answer[3] = 1*2*3 = 6


解法:左右乘积列表(推荐)⭐

思路: - 左侧乘积:当前元素左边所有元素的乘积 - 右侧乘积:当前元素右边所有元素的乘积 - answer[i] = left[i] * right[i]

Python
def product_except_self(nums):
    """
    除自身以外数组的乘积
    时间:O(n)
    空间:O(1)(不包括输出数组)
    """
    n = len(nums)
    answer = [1] * n

    # 计算左侧乘积
    left_product = 1
    for i in range(n):
        answer[i] = left_product
        left_product *= nums[i]

    # 计算右侧乘积并更新answer
    right_product = 1
    for i in range(n - 1, -1, -1):
        answer[i] *= right_product
        right_product *= nums[i]

    return answer

执行过程演示

Text Only
输入:nums = [1,2,3,4]

初始化:answer = [1,1,1,1]

第1步:计算左侧乘积(从左到右)
i=0: answer[0]=1,      left_product=1*1=1
i=1: answer[1]=1,      left_product=1*2=2
i=2: answer[2]=2,      left_product=2*3=6
i=3: answer[3]=6,      left_product=6*4=24

answer = [1,1,2,6](左侧乘积)

第2步:计算右侧乘积并更新(从右到左)
i=3: answer[3]=6*1=6,      right_product=1*4=4
i=2: answer[2]=2*4=8,      right_product=4*3=12
i=1: answer[1]=1*12=12,    right_product=12*2=24
i=0: answer[0]=1*24=24,    right_product=24*1=24

answer = [24,12,8,6] ✓

验证:
- answer[0] = 24 = 2*3*4 ✓
- answer[1] = 12 = 1*3*4 ✓
- answer[2] = 8  = 1*2*4 ✓
- answer[3] = 6  = 1*2*3 ✓


题目7:三数之和(3Sum)⭐⭐⭐⭐⭐

题目链接LeetCode 15

难度:中等

问题描述: 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 abc,使得 a + b + c = 0?找出所有和为 0 且不重复的三元组。

示例

Text Only
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]


解法:排序 + 双指针(推荐)⭐

思路: 1. 先排序数组 2. 固定第一个元素,用双指针找另外两个元素 3. 跳过重复元素

Python
def three_sum(nums):
    """
    三数之和
    时间:O(n²)
    空间:O(1)
    """
    nums.sort()
    result = []
    n = len(nums)

    for i in range(n - 2):
        # 跳过重复的第一个元素
        if i > 0 and nums[i] == nums[i - 1]:
            continue

        # 双指针
        left, right = i + 1, n - 1

        while left < right:
            current_sum = nums[i] + nums[left] + nums[right]

            if current_sum == 0:
                result.append([nums[i], nums[left], nums[right]])

                # 跳过重复元素
                while left < right and nums[left] == nums[left + 1]:
                    left += 1
                while left < right and nums[right] == nums[right - 1]:
                    right -= 1

                left += 1
                right -= 1

            elif current_sum < 0:
                left += 1
            else:
                right -= 1

    return result

执行过程演示

Text Only
输入:nums = [-1,0,1,2,-1,-4]

第1步:排序
  [-4,-1,-1,0,1,2]

第2步:遍历
i=0, nums[i]=-4:
  - left=1, right=5
  - -4 + (-1) + 2 = -3 < 0, left++
  - -4 + (-1) + 2 = -3 < 0, left++
  - ... (left继续增加,但无法找到和为0的组合)

i=1, nums[i]=-1:
  - left=2, right=5
  - -1 + (-1) + 2 = 0 ✓ 找到 [-1,-1,2]
  - left=3, right=4
  - -1 + 0 + 1 = 0 ✓ 找到 [-1,0,1]

i=2, nums[i]=-1:
  - 跳过(与i=1重复)

i=3, nums[i]=0:
  - left=4, right=5
  - 0 + 1 + 2 = 3 > 0, right--
  - left >= right, 结束

结果:[[-1,-1,2], [-1,0,1]] ✓


题目8:搜索二维矩阵II(Search a 2D Matrix II)⭐⭐⭐⭐

题目链接LeetCode 240

难度:中等

问题描述: 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target。该矩阵具有以下特性: - 每行的元素从左到右升序排列 - 每列的元素从上到下升序排列

示例

Text Only
输入:matrix = [
  [1,4,7,11,15],
  [2,5,8,12,19],
  [3,6,9,16,22],
  [10,13,14,17,24],
  [18,21,23,26,30]
], target = 5
输出:true


解法:从右上角开始搜索(推荐)⭐

思路: - 从右上角开始 - 如果当前元素 > target,向左移动(列减小) - 如果当前元素 < target,向下移动(行增加)

Python
def search_matrix(matrix, target):
    """
    搜索二维矩阵II
    时间:O(m + n)
    空间:O(1)
    """
    if not matrix or not matrix[0]:
        return False

    m, n = len(matrix), len(matrix[0])

    # 从右上角开始
    row, col = 0, n - 1

    while row < m and col >= 0:
        current = matrix[row][col]

        if current == target:
            return True
        elif current > target:
            # 当前值太大,向左移动
            col -= 1
        else:
            # 当前值太小,向下移动
            row += 1

    return False

执行过程演示

Text Only
矩阵:
[ 1, 4, 7,11,15]
[ 2, 5, 8,12,19]
[ 3, 6, 9,16,22]
[10,13,14,17,24]
[18,21,23,26,30]

target = 5

从右上角(0,4)=15开始:
1. 15 > 5, 向左移动到 (0,3)=11
2. 11 > 5, 向左移动到 (0,2)=7
3. 7 > 5, 向左移动到 (0,1)=4
4. 4 < 5, 向下移动到 (1,1)=5
5. 5 == 5 ✓ 找到!

返回:True


题目9:合并区间(Merge Intervals)⭐⭐⭐⭐

题目链接LeetCode 56

难度:中等

问题描述: 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi]。请你合并所有重叠的区间,并返回一个不重叠的区间数组。

示例

Text Only
输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠,将它们合并为 [1,6]。


解法:排序 + 遍历(推荐)⭐

Python
def merge(intervals):
    """
    合并区间
    时间:O(n log n)
    空间:O(1)
    """
    if not intervals:
        return []

    # 按区间起点排序
    intervals.sort(key=lambda x: x[0])  # lambda匿名函数:简洁的单行函数

    result = []
    current = intervals[0]

    for interval in intervals[1:]:  # 切片操作:[start:end:step]提取子序列
        # 如果有重叠(当前区间的起点 <= 上一个区间的终点)
        if interval[0] <= current[1]:
            # 合并:更新终点为两者中较大的
            current[1] = max(current[1], interval[1])
        else:
            # 无重叠,保存当前区间,开始新区间
            result.append(current)
            current = interval

    # 添加最后一个区间
    result.append(current)

    return result

执行过程演示

Text Only
输入:[[1,3],[2,6],[8,10],[15,18]]

第1步:排序(已排序)
  [[1,3],[2,6],[8,10],[15,18]]

第2步:遍历合并
初始:current = [1,3]

[2,6]:
  - 2 <= 3,有重叠
  - 合并:current = [1, max(3,6)] = [1,6]

[8,10]:
  - 8 > 6,无重叠
  - 保存 [1,6]
  - current = [8,10]

[15,18]:
  - 15 > 10,无重叠
  - 保存 [8,10]
  - current = [15,18]

最后:添加 [15,18]

结果:[[1,6],[8,10],[15,18]] ✓


题目10:矩阵置零(Set Matrix Zeroes)⭐⭐⭐

题目链接LeetCode 73

难度:中等

问题描述: 给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。请使用原地算法。

示例

Text Only
输入:matrix = [
  [1,1,1],
  [1,0,1],
  [1,1,1]
]
输出:[
  [1,0,1],
  [0,0,0],
  [1,0,1]
]


解法:使用首行首列标记(推荐)⭐

思路: - 用第一行和第一列作为标记数组 - 用两个变量记录第一行和第一列本身是否有0

Python
def set_zeroes(matrix):
    """
    矩阵置零
    时间:O(m*n)
    空间:O(1)
    """
    if not matrix or not matrix[0]:
        return

    m, n = len(matrix), len(matrix[0])

    # 标记第一行和第一列是否有0
    first_row_has_zero = any(matrix[0][j] == 0 for j in range(n))
    first_col_has_zero = any(matrix[i][0] == 0 for i in range(m))

    # 用第一行和第一列标记0的位置
    for i in range(1, m):
        for j in range(1, n):
            if matrix[i][j] == 0:
                matrix[i][0] = 0
                matrix[0][j] = 0

    # 根据标记置零
    for i in range(1, m):
        for j in range(1, n):
            if matrix[i][0] == 0 or matrix[0][j] == 0:
                matrix[i][j] = 0

    # 处理第一行和第一列
    if first_row_has_zero:
        for j in range(n):
            matrix[0][j] = 0

    if first_col_has_zero:
        for i in range(m):
            matrix[i][0] = 0

链表(15题)

题目11:反转链表(Reverse Linked List)⭐⭐⭐⭐⭐

题目链接LeetCode 206

难度:简单

问题描述: 给你单链表的头节点 head,请你反转链表,并返回反转后的链表。

示例

Text Only
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]


解法1:迭代法(推荐)⭐

Python
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

def reverse_list(head):
    """
    反转链表(迭代)
    时间:O(n)
    空间:O(1)
    """
    prev = None
    current = head

    while current:
        # 保存下一个节点
        next_node = current.next
        # 反转指针
        current.next = prev
        # 移动指针
        prev = current
        current = next_node

    return prev

执行过程演示

Text Only
初始:1 -> 2 -> 3 -> 4 -> 5

第1次迭代:
  - current = 1
  - next_node = 2
  - 1.next = None
  - prev = 1
  - 状态:None <- 1    2 -> 3 -> 4 -> 5

第2次迭代:
  - current = 2
  - next_node = 3
  - 2.next = 1
  - prev = 2
  - 状态:None <- 1 <- 2    3 -> 4 -> 5

第3次迭代:
  - current = 3
  - next_node = 4
  - 3.next = 2
  - prev = 3
  - 状态:None <- 1 <- 2 <- 3    4 -> 5

第4次迭代:
  - current = 4
  - next_node = 5
  - 4.next = 3
  - prev = 4
  - 状态:None <- 1 <- 2 <- 3 <- 4    5

第5次迭代:
  - current = 5
  - next_node = None
  - 5.next = 4
  - prev = 5
  - 状态:None <- 1 <- 2 <- 3 <- 4 <- 5

返回:prev = 5(新头节点)


解法2:递归法

Python
def reverse_list_recursive(head):
    """
    反转链表(递归)
    时间:O(n)
    空间:O(n)(递归栈)
    """
    if not head or not head.next:
        return head

    # 递归反转后面的链表
    new_head = reverse_list_recursive(head.next)

    # 反转当前节点和下一个节点的指针
    head.next.next = head
    head.next = None

    return new_head

题目12:合并两个有序链表(Merge Two Sorted Lists)⭐⭐⭐⭐⭐

题目链接LeetCode 21

难度:简单

问题描述: 将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例

Text Only
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]


解法:迭代(推荐)⭐

Python
def merge_two_lists(l1, l2):
    """
    合并两个有序链表
    时间:O(m + n)
    空间:O(1)
    """
    # 创建虚拟头节点
    dummy = ListNode(0)
    current = dummy

    # 比较并合并
    while l1 and l2:
        if l1.val <= l2.val:
            current.next = l1
            l1 = l1.next
        else:
            current.next = l2
            l2 = l2.next
        current = current.next

    # 连接剩余节点
    current.next = l1 if l1 else l2

    return dummy.next

题目13:环形链表(Linked List Cycle)⭐⭐⭐⭐

题目链接LeetCode 141

难度:简单

问题描述: 给你一个链表的头节点 head,判断链表中是否有环。


解法:快慢指针(推荐)⭐

Python
def has_cycle(head):
    """
    环形链表(快慢指针)
    时间:O(n)
    空间:O(1)
    """
    if not head or not head.next:
        return False

    slow = head
    fast = head

    while fast and fast.next:
        slow = slow.next      # 慢指针走1步
        fast = fast.next.next # 快指针走2步

        # 如果相遇,说明有环
        if slow == fast:
            return True

    return False

题目14:环形链表II(Linked List Cycle II)⭐⭐⭐⭐⭐

题目链接LeetCode 142

难度:中等

问题描述: 给定一个链表,返回链表开始入环的第一个节点。如果链表无环,则返回 null


解法:快慢指针 + 数学(推荐)⭐

Python
def detect_cycle(head):
    """
    环形链表II
    时间:O(n)
    空间:O(1)
    """
    if not head or not head.next:
        return None

    # 第1步:判断是否有环
    slow = head
    fast = head

    has_cycle = False
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next

        if slow == fast:
            has_cycle = True
            break

    if not has_cycle:
        return None

    # 第2步:找到环的入口
    # 一个指针从head开始,一个从相遇点开始
    # 相同速度前进,相遇点就是环入口
    ptr1 = head
    ptr2 = slow

    while ptr1 != ptr2:
        ptr1 = ptr1.next
        ptr2 = ptr2.next

    return ptr1

数学原理

Text Only
设:
- 头节点到环入口距离为 a
- 环入口到相遇点距离为 b
- 相遇点到环入口距离为 c
- 环长度为 b + c

快指针走的距离:a + b + c + b = a + 2b + c
慢指针走的距离:a + b

快指针速度是慢指针的2倍:
a + 2b + c = 2(a + b)
=> a + c = 0

因此:从head出发走a步,从相遇点出发走c步,会在环入口相遇


题目15:回文链表(Palindrome Linked List)⭐⭐⭐⭐

题目链接LeetCode 234

难度:简单

问题描述: 给你一个单链表的头节点 head,请你判断该链表是否为回文链表。


解法:反转后半部分(推荐)⭐

Python
def is_palindrome(head):
    """
    回文链表
    时间:O(n)
    空间:O(1)
    """
    if not head or not head.next:
        return True

    # 第1步:找到中点
    slow = head
    fast = head

    while fast.next and fast.next.next:
        slow = slow.next
        fast = fast.next.next

    # 第2步:反转后半部分
    second_half = reverse_list(slow.next)

    # 第3步:比较前后两部分
    first_half = head
    result = True

    while second_half:
        if first_half.val != second_half.val:
            result = False
            break
        first_half = first_half.next
        second_half = second_half.next

    # 第4步:恢复链表(可选)
    slow.next = reverse_list(second_half)

    return result

树(20题)

题目16:二叉树的最大深度(Maximum Depth of Binary Tree)⭐⭐⭐⭐

题目链接LeetCode 104

难度:简单

问题描述: 给定一个二叉树,找出其最大深度。


解法:递归(推荐)⭐

Python
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def max_depth(root):
    """
    二叉树的最大深度
    时间:O(n)
    空间:O(h)
    """
    if not root:
        return 0

    left_depth = max_depth(root.left)
    right_depth = max_depth(root.right)

    return max(left_depth, right_depth) + 1

题目17:验证二叉搜索树(Validate BST)⭐⭐⭐⭐⭐

题目链接LeetCode 98

难度:中等

问题描述: 给定一个二叉树,判断其是否是一个有效的二叉搜索树(BST)。


解法:递归 + 上下界(推荐)⭐

Python
def is_valid_bst(root):
    """
    验证二叉搜索树
    时间:O(n)
    空间:O(h)
    """
    def validate(node, low, high):
        if not node:
            return True

        # 检查当前节点值是否在范围内
        if not (low < node.val < high):
            return False

        # 递归检查左右子树
        return (validate(node.left, low, node.val) and
                validate(node.right, node.val, high))

    return validate(root, float('-inf'), float('inf'))

题目18:对称二叉树(Symmetric Tree)⭐⭐⭐⭐

题目链接LeetCode 101

难度:简单

问题描述: 给定一个二叉树,检查它是否轴对称。


解法:递归(推荐)⭐

Python
def is_symmetric(root):
    """
    对称二叉树
    时间:O(n)
    空间:O(h)
    """
    if not root:
        return True

    def is_mirror(left, right):
        if not left and not right:
            return True
        if not left or not right:
            return False

        return (left.val == right.val and
                is_mirror(left.left, right.right) and
                is_mirror(left.right, right.left))

    return is_mirror(root.left, root.right)

题目19:层序遍历(Binary Tree Level Order Traversal)⭐⭐⭐⭐⭐

题目链接LeetCode 102

难度:中等

问题描述: 给你二叉树的根节点,返回其节点值的层序遍历。(即逐层地,从左到右访问所有节点)。


解法:BFS(推荐)⭐

Python
from collections import deque

def level_order(root):
    """
    层序遍历
    时间:O(n)
    空间:O(n)
    """
    if not root:
        return []

    result = []
    queue = deque([root])

    while queue:
        level_size = len(queue)
        level = []

        for _ in range(level_size):
            node = queue.popleft()
            level.append(node.val)

            if node.left:
                queue.append(node.left)
            if node.right:
                queue.append(node.right)

        result.append(level)

    return result

题目20:二叉树展开为链表(Flatten Binary Tree to Linked List)⭐⭐⭐⭐

题目链接LeetCode 114

难度:中等

问题描述: 给你二叉树的根节点,请你将它展开为一个单链表。 - 展开后的单链表应该同样使用 TreeNode,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null。 - 展开后的单链表应该与二叉树先序遍历顺序相同。


解法:迭代(推荐)⭐

Python
def flatten(root):
    """
    二叉树展开为链表
    时间:O(n)
    空间:O(1)
    """
    if not root:
        return

    current = root

    while current:
        if current.left:
            # 找到左子树的最右节点
            rightmost = current.left
            while rightmost.right:
                rightmost = rightmost.right

            # 将右子树接到左子树的最右节点
            rightmost.right = current.right

            # 将左子树移到右子树
            current.right = current.left
            current.left = None

        # 移动到下一个节点
        current = current.right

动态规划(20题)

题目21:爬楼梯(Climbing Stairs)⭐⭐⭐⭐⭐

题目链接LeetCode 70

难度:简单

问题描述: 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 12 个台阶。你有多少种不同的方法可以爬到楼顶呢?


解法1:动态规划(推荐)⭐

Python
def climb_stairs(n):
    """
    爬楼梯
    时间:O(n)
    空间:O(1)
    """
    if n <= 2:
        return n

    # dp[i] = dp[i-1] + dp[i-2]
    prev, curr = 1, 2

    for _ in range(3, n + 1):
        prev, curr = curr, prev + curr

    return curr

解法2:矩阵快速幂(进阶)

Python
def climb_stairs_fast(n):
    """
    爬楼梯(矩阵快速幂)
    时间:O(log n)
    空间:O(1)
    """
    def matrix_pow(mat, power):
        result = [[1, 0], [0, 1]]  # 单位矩阵

        while power:
            if power % 2 == 1:
                result = matrix_multiply(result, mat)
            mat = matrix_multiply(mat, mat)
            power //= 2

        return result

    def matrix_multiply(a, b):
        return [
            [a[0][0] * b[0][0] + a[0][1] * b[1][0],
             a[0][0] * b[0][1] + a[0][1] * b[1][1]],
            [a[1][0] * b[0][0] + a[1][1] * b[1][0],
             a[1][0] * b[0][1] + a[1][1] * b[1][1]]
        ]

    if n <= 2:
        return n

    mat = [[1, 1], [1, 0]]
    result = matrix_pow(mat, n - 1)

    return result[0][0]

题目22:打家劫舍(House Robber)⭐⭐⭐⭐⭐

题目链接LeetCode 198

难度:中等

问题描述: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统。如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,今晚能够偷窃到的最高金额。


解法:动态规划(推荐)⭐

Python
def rob(nums):
    """
    打家劫舍
    时间:O(n)
    空间:O(1)
    """
    if not nums:
        return 0
    if len(nums) <= 2:
        return max(nums)

    # dp[i] = max(dp[i-1], dp[i-2] + nums[i])
    prev2 = nums[0]           # dp[i-2]
    prev1 = max(nums[0], nums[1])  # dp[i-1]

    for i in range(2, len(nums)):
        current = max(prev1, prev2 + nums[i])
        prev2, prev1 = prev1, current

    return prev1

状态转移方程

Text Only
对于第i个房子,有两种选择:
1. 不偷第i个房子:最大金额 = dp[i-1]
2. 偷第i个房子:最大金额 = dp[i-2] + nums[i]

dp[i] = max(dp[i-1], dp[i-2] + nums[i])


题目23:零钱兑换(Coin Change)⭐⭐⭐⭐⭐

题目链接LeetCode 322

难度:中等

问题描述: 给你一个整数数组 coins,表示不同面额的硬币;以及一个整数 amount,表示总金额。计算并返回可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1


解法:动态规划(推荐)⭐

Python
def coin_change(coins, amount):
    """
    零钱兑换
    时间:O(amount * len(coins))
    空间:O(amount)
    """
    # dp[i] = 凑成金额i所需的最少硬币数
    dp = [float('inf')] * (amount + 1)
    dp[0] = 0  # 凑成金额0需要0个硬币

    for coin in coins:
        for i in range(coin, amount + 1):
            dp[i] = min(dp[i], dp[i - coin] + 1)

    return dp[amount] if dp[amount] != float('inf') else -1

执行过程演示

Text Only
输入:coins = [1,2,5], amount = 11

初始化:dp = [0,inf,inf,inf,inf,inf,inf,inf,inf,inf,inf,inf]

使用coin=1更新:
  dp = [0,1,2,3,4,5,6,7,8,9,10,11]

使用coin=2更新:
  dp = [0,1,1,2,2,3,3,4,4,5,5,6]

使用coin=5更新:
  dp = [0,1,1,2,2,1,2,2,3,3,2,3]

结果:3(5+5+1)


题目24:最长递增子序列(Longest Increasing Subsequence)⭐⭐⭐⭐⭐

题目链接LeetCode 300

难度:中等

问题描述: 给你一个整数数组 nums,找到其中最长严格递增子序列的长度。


解法1:动态规划(基础)⭐

Python
def length_of_lis(nums):
    """
    最长递增子序列(DP)
    时间:O(n²)
    空间:O(n)
    """
    if not nums:
        return 0

    n = len(nums)
    # dp[i] = 以nums[i]结尾的最长递增子序列长度
    dp = [1] * n

    for i in range(n):
        for j in range(i):
            if nums[j] < nums[i]:
                dp[i] = max(dp[i], dp[j] + 1)

    return max(dp)

解法2:二分查找(进阶)⭐⭐

Python
import bisect

def length_of_lis_binary(nums):
    """
    最长递增子序列(二分查找)
    时间:O(n log n)
    空间:O(n)
    """
    if not nums:
        return 0

    # tails[i] = 长度为i+1的递增子序列的最小末尾
    tails = []

    for num in nums:
        # 二分查找第一个 >= num 的位置
        idx = bisect.bisect_left(tails, num)

        if idx == len(tails):
            tails.append(num)
        else:
            tails[idx] = num

    return len(tails)

执行过程演示

Text Only
输入:nums = [10,9,2,5,3,7,101,18]

初始化:tails = []

num=10:  tails = [10]
num=9:   tails = [9]      (替换10)
num=2:   tails = [2]      (替换9)
num=5:   tails = [2,5]
num=3:   tails = [2,3]    (替换5)
num=7:   tails = [2,3,7]
num=101: tails = [2,3,7,101]
num=18:  tails = [2,3,7,18]  (替换101)

结果:4
子序列:[2,3,7,101] 或 [2,3,7,18]


题目25:完全平方数(Perfect Squares)⭐⭐⭐⭐

题目链接LeetCode 279

难度:中等

问题描述: 给你一个整数 n,返回和为 n 的完全平方数的最少数量。


解法:动态规划(推荐)⭐

Python
def num_squares(n):
    """
    完全平方数
    时间:O(n * sqrt(n))
    空间:O(n)
    """
    # dp[i] = 和为i的完全平方数的最少数量
    dp = [float('inf')] * (n + 1)
    dp[0] = 0

    for i in range(1, n + 1):
        j = 1
        while j * j <= i:
            dp[i] = min(dp[i], dp[i - j * j] + 1)
            j += 1

    return dp[n]

图(10题)

题目26:课程表(Course Schedule)⭐⭐⭐⭐⭐

题目链接LeetCode 207

难度:中等

问题描述: 你必须修读 numCourses 门课程,记为 0numCourses-1。在选修某些课程之前需要一些先修课程。先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi],表示如果要学习课程 ai 则必须先学习课程 bi。判断是否可能完成所有课程的学习?


解法:拓扑排序(推荐)⭐

Python
from collections import deque

def can_finish(num_courses, prerequisites):
    """
    课程表(拓扑排序)
    时间:O(V + E)
    空间:O(V + E)
    """
    # 构建邻接表和入度数组
    adj = [[] for _ in range(num_courses)]
    in_degree = [0] * num_courses

    for course, prereq in prerequisites:
        adj[prereq].append(course)
        in_degree[course] += 1

    # 将入度为0的节点加入队列
    queue = deque([i for i in range(num_courses) if in_degree[i] == 0])

    # BFS拓扑排序
    count = 0
    while queue:
        node = queue.popleft()
        count += 1

        for neighbor in adj[node]:
            in_degree[neighbor] -= 1
            if in_degree[neighbor] == 0:
                queue.append(neighbor)

    # 如果所有节点都被访问,说明没有环
    return count == num_courses

题目27:课程表II(Course Schedule II)⭐⭐⭐⭐⭐

题目链接LeetCode 210

难度:中等

问题描述: 现在你总共有 numCourses 门课需要选,记为 0numCourses-1。给定一个数组 prerequisites,其中 prerequisites[i] = [ai, bi],表示在选修课程 ai 前必须先选修 bi。返回你为了学完所有课程所安排的学习顺序。可能会有多个正确的顺序,你只要返回任意一种就可以了。如果不可能完成所有课程,返回一个空数组。


解法:拓扑排序(推荐)⭐

Python
def find_order(num_courses, prerequisites):
    """
    课程表II
    时间:O(V + E)
    空间:O(V + E)
    """
    # 构建邻接表和入度数组
    adj = [[] for _ in range(num_courses)]
    in_degree = [0] * num_courses

    for course, prereq in prerequisites:
        adj[prereq].append(course)
        in_degree[course] += 1

    # BFS拓扑排序
    queue = deque([i for i in range(num_courses) if in_degree[i] == 0])
    result = []

    while queue:
        node = queue.popleft()
        result.append(node)

        for neighbor in adj[node]:
            in_degree[neighbor] -= 1
            if in_degree[neighbor] == 0:
                queue.append(neighbor)

    # 判断是否有环
    return result if len(result) == num_courses else []

题目28:被围绕的区域(Surrounded Regions)⭐⭐⭐⭐

题目链接LeetCode 130

难度:中等

问题描述: 给你一个 m x n 的矩阵 board,由若干字符 'X''O',找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O''X' 填充。


解法:从边界开始DFS(推荐)⭐

Python
def solve(board):
    """
    被围绕的区域
    时间:O(m * n)
    空间:O(m * n)
    """
    if not board or not board[0]:
        return

    m, n = len(board), len(board[0])

    def dfs(i, j):
        """标记与边界相连的O"""
        if i < 0 or i >= m or j < 0 or j >= n:
            return
        if board[i][j] != 'O':
            return

        # 标记为临时字符
        board[i][j] = 'T'

        # 递归标记四个方向
        dfs(i + 1, j)
        dfs(i - 1, j)
        dfs(i, j + 1)
        dfs(i, j - 1)

    # 第1步:从边界开始,标记所有与边界相连的O
    for i in range(m):
        for j in range(n):
            if i == 0 or i == m - 1 or j == 0 or j == n - 1:
                if board[i][j] == 'O':
                    dfs(i, j)

    # 第2步:遍历整个矩阵
    for i in range(m):
        for j in range(n):
            if board[i][j] == 'O':
                # 被包围的O,改为X
                board[i][j] = 'X'
            elif board[i][j] == 'T':
                # 与边界相连的O,恢复为O
                board[i][j] = 'O'

排序/搜索(15题)

题目29:合并两个有序数组(Merge Sorted Array)⭐⭐⭐

题目链接LeetCode 88

难度:简单

问题描述: 给你两个按非递减顺序排列的整数数组 nums1nums2,另有两个整数 mn,分别表示 nums1nums2 中的元素数目。请你合并 nums2nums1 中,使合并后的数组同样按非递减顺序排列。

示例

Text Only
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]


解法:从后向前合并(推荐)⭐

Python
def merge(nums1, m, nums2, n):
    """
    合并两个有序数组
    时间:O(m + n)
    空间:O(1)
    """
    # 三个指针
    p1 = m - 1      # nums1的最后一个元素
    p2 = n - 1      # nums2的最后一个元素
    p = m + n - 1   # 合并后的最后一个位置

    # 从后向前合并
    while p1 >= 0 and p2 >= 0:
        if nums1[p1] > nums2[p2]:
            nums1[p] = nums1[p1]
            p1 -= 1
        else:
            nums1[p] = nums2[p2]
            p2 -= 1
        p -= 1

    # 复制nums2剩余元素
    while p2 >= 0:
        nums1[p] = nums2[p2]
        p2 -= 1
        p -= 1

执行过程演示

Text Only
输入:nums1 = [1,2,3,0,0,0], m = 3
      nums2 = [2,5,6], n = 3

初始:p1=2, p2=2, p=5
nums1 = [1,2,3,0,0,0]
nums2 = [2,5,6]

第1次比较:
  nums1[2]=3 vs nums2[2]=6
  3 < 6,nums1[5]=6
  p2=1, p=4
  nums1 = [1,2,3,0,0,6]

第2次比较:
  nums1[2]=3 vs nums2[1]=5
  3 < 5,nums1[4]=5
  p2=0, p=3
  nums1 = [1,2,3,0,5,6]

第3次比较:
  nums1[2]=3 vs nums2[0]=2
  3 > 2,nums1[3]=3
  p1=1, p=2
  nums1 = [1,2,3,3,5,6]

第4次比较:
  nums1[1]=2 vs nums2[0]=2
  2 = 2,nums1[2]=2
  p2=-1, p=1
  nums1 = [1,2,2,3,5,6]

p2 < 0,结束

结果:[1,2,2,3,5,6] ✓


题目30:第一个错误的版本(First Bad Version)⭐⭐⭐

题目链接LeetCode 278

难度:简单

问题描述: 你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。假设你有 n 个版本 [1, 2, ..., n],你想找出导致之后所有版本出错的第一个错误的版本。你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。


解法:二分查找(推荐)⭐

Python
def first_bad_version(n):
    """
    第一个错误的版本
    时间:O(log n)
    空间:O(1)
    """
    left, right = 1, n

    while left < right:
        mid = left + (right - left) // 2

        if is_bad_version(mid):
            # mid是错误版本,第一个错误版本在[left, mid]
            right = mid
        else:
            # mid是正确版本,第一个错误版本在[mid+1, right]
            left = mid + 1

    return left

题目31:搜索插入位置(Search Insert Position)⭐⭐⭐

题目链接LeetCode 35

难度:简单

问题描述: 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。


解法:二分查找(推荐)⭐

Python
def search_insert(nums, target):
    """
    搜索插入位置
    时间:O(log n)
    空间:O(1)
    """
    left, right = 0, len(nums)

    while left < right:
        mid = left + (right - left) // 2

        if nums[mid] < target:
            left = mid + 1
        else:
            right = mid

    return left

题目32:搜索二维矩阵(Search a 2D Matrix)⭐⭐⭐⭐

题目链接LeetCode 74

难度:中等

问题描述: 编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性: - 每行中的整数从左到右按升序排列 - 每行的第一个整数大于前一行的最后一个整数

示例

Text Only
输入:matrix = [
  [1,3,5,7],
  [10,11,16,20],
  [23,30,34,60]
], target = 3
输出:true


解法:二分查找(推荐)⭐

Python
def search_matrix(matrix, target):
    """
    搜索二维矩阵
    时间:O(log(m * n))
    空间:O(1)
    """
    if not matrix or not matrix[0]:
        return False

    m, n = len(matrix), len(matrix[0])
    left, right = 0, m * n - 1

    while left <= right:
        mid = left + (right - left) // 2
        # 将一维索引转换为二维坐标
        row = mid // n
        col = mid % n

        if matrix[row][col] == target:
            return True
        elif matrix[row][col] < target:
            left = mid + 1
        else:
            right = mid - 1

    return False

题目33:在排序数组中查找元素的第一个和最后一个位置⭐⭐⭐⭐⭐

题目链接LeetCode 34

难度:中等

问题描述: 给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 [-1, -1]


解法:二分查找(推荐)⭐

Python
def search_range(nums, target):
    """
    查找元素的第一个和最后一个位置
    时间:O(log n)
    空间:O(1)
    """
    def find_left():
        """找第一个位置"""
        left, right = 0, len(nums)
        while left < right:
            mid = left + (right - left) // 2
            if nums[mid] < target:
                left = mid + 1
            else:
                right = mid
        return left

    def find_right():
        """找最后一个位置"""
        left, right = 0, len(nums)
        while left < right:
            mid = left + (right - left) // 2
            if nums[mid] <= target:
                left = mid + 1
            else:
                right = mid
        return left - 1

    if not nums:
        return [-1, -1]

    left_idx = find_left()
    right_idx = find_right()

    if left_idx <= right_idx and right_idx < len(nums) and nums[left_idx] == target:
        return [left_idx, right_idx]

    return [-1, -1]

题目34:寻找峰值(Find Peak Element)⭐⭐⭐⭐

题目链接LeetCode 162

难度:中等

问题描述: 峰值元素是指其值严格大于左右相邻值的元素。给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可。你可以假设 nums[-1] = nums[n] = -∞


解法:二分查找(推荐)⭐

Python
def find_peak_element(nums):
    """
    寻找峰值
    时间:O(log n)
    空间:O(1)
    """
    if not nums:
        return -1

    left, right = 0, len(nums) - 1

    while left < right:
        mid = left + (right - left) // 2

        if nums[mid] > nums[mid + 1]:
            # 峰值在[left, mid]
            right = mid
        else:
            # 峰值在[mid+1, right]
            left = mid + 1

    return left

📝 总结

刷题策略

1. 按难度刷题

Text Only
第1阶段(简单题):
- 两数之和、买卖股票、最大子数组和
- 反转链表、合并两个有序链表
- 爬楼梯、打家劫舍

第2阶段(中等题):
- 三数之和、合并区间
- 验证BST、层序遍历
- 零钱兑换、最长递增子序列

第3阶段(困难题):
- (根据自己需求选择)

2. 按标签刷题

Text Only
数组:1-10
链表:11-15
树:16-20
动态规划:21-25
图:26-28
排序/搜索:29-34

3. 重复刷题

Text Only
第1遍:理解题意,能做出来
第2遍:优化解法,多种思路
第3遍:限时完成,写最优解

面试高频题Top 20

  1. 两数之和 ⭐⭐⭐⭐⭐
  2. 买卖股票的最佳时机 ⭐⭐⭐⭐⭐
  3. 最大子数组和 ⭐⭐⭐⭐⭐
  4. 三数之和 ⭐⭐⭐⭐⭐
  5. 反转链表 ⭐⭐⭐⭐⭐
  6. 合并两个有序链表 ⭐⭐⭐⭐⭐
  7. 环形链表II ⭐⭐⭐⭐⭐
  8. 二叉树的最大深度 ⭐⭐⭐⭐
  9. 验证二叉搜索树 ⭐⭐⭐⭐⭐
  10. 层序遍历 ⭐⭐⭐⭐⭐
  11. 爬楼梯 ⭐⭐⭐⭐⭐
  12. 打家劫舍 ⭐⭐⭐⭐⭐
  13. 零钱兑换 ⭐⭐⭐⭐⭐
  14. 最长递增子序列 ⭐⭐⭐⭐⭐
  15. 课程表 ⭐⭐⭐⭐⭐
  16. 合并区间 ⭐⭐⭐⭐
  17. 搜索插入位置 ⭐⭐⭐⭐
  18. 在排序数组中查找元素的第一个和最后一个位置 ⭐⭐⭐⭐⭐
  19. 除自身以外数组的乘积 ⭐⭐⭐⭐
  20. 搜索二维矩阵 ⭐⭐⭐⭐

继续努力!每天刷2-3题,2-3个月后就能轻松应对大厂面试!💪