LeetCode算法题详解 42:接雨水

目录

  • 1.问题描述
  • 2.问题分析
    • [2.1 理解题目](#2.1 理解题目)
    • [2.2 关键挑战](#2.2 关键挑战)
    • [2.3 核心洞察](#2.3 核心洞察)
    • [2.4 破题关键](#2.4 破题关键)
  • [3 算法设计与实现](#3 算法设计与实现)
    • [3.1 动态规划法(基础解法)](#3.1 动态规划法(基础解法))
    • [3.2 双指针法](#3.2 双指针法)
    • [3.3 单调栈法](#3.3 单调栈法)
    • [3.4 暴力枚举法](#3.4 暴力枚举法)
    • [3.5 双指针优化法](#3.5 双指针优化法)
  • [4 性能分析与对比](#4 性能分析与对比)
    • [4.1 复杂度对比](#4.1 复杂度对比)
    • [4.2 性能分析](#4.2 性能分析)
    • [4.3 正确性证明](#4.3 正确性证明)
  • 5.边界情况处理
    • [5.1 常见边界情况](#5.1 常见边界情况)
    • [5.2 边界处理技巧](#5.2 边界处理技巧)
  • 6.扩展与变体
    • [6.1 二维接雨水问题](#6.1 二维接雨水问题)
    • [6.2 最多接雨水问题](#6.2 最多接雨水问题)
    • [6.3 接雨水II(有渗透问题)](#6.3 接雨水II(有渗透问题))
    • [6.4 实时接雨水监控](#6.4 实时接雨水监控)
  • 7.总结
    • [7.1 核心知识点总结](#7.1 核心知识点总结)
    • [7.2 算法思维提升](#7.2 算法思维提升)
    • [7.3 实际应用场景](#7.3 实际应用场景)
    • [7.4 面试建议](#7.4 面试建议)

1.问题描述

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1

复制代码
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。

示例 2

复制代码
输入:height = [4,2,0,3,2,5]
输出:9

约束条件

  • n == height.length
  • 1 <= n <= 2 × 10^4
  • 0 <= height[i] <= 10^5

2.问题分析

2.1 理解题目

本题要求计算柱状图中能接住的雨水量。每个柱子宽度为1,雨水只能储存在柱子之间的凹陷处。关键要点:

  1. 雨水计算原理:对于每个位置,能接的雨水量取决于其左右两侧最高柱子的较小值
  2. 木桶原理:每个位置的水量受限于左右两侧最高柱子中较矮的那个
  3. 边界处理:两端的柱子不能接水,因为至少需要两侧都有更高的柱子才能形成凹陷
  4. 水量公式:对于位置i,水量 = min(左边最高, 右边最高) - height[i](如果结果为正)

2.2 关键挑战

  1. 数据规模大:数组长度可达2×10^4,需要高效算法
  2. 多种解法:有多种解法,各有优缺点
  3. 边界条件:需要考虑数组长度小于3、递增递减序列等特殊情况
  4. 算法选择:需要根据场景选择最合适的解法

2.3 核心洞察

  1. 问题转化:将接雨水问题转化为求每个位置左右两侧最大值的问题
  2. 预处理思想:可以预先计算每个位置的左右最大值,避免重复计算
  3. 动态规划思路:使用两个数组分别存储每个位置左侧和右侧的最大值
  4. 双指针优化:可以使用双指针在一次遍历中解决问题,空间复杂度O(1)
  5. 单调栈应用:使用单调递减栈可以处理复杂形状的雨水收集

2.4 破题关键

  1. 基本思路:对于每个位置,计算其左右两侧的最高柱子,取较小值减去当前高度
  2. 动态规划:使用两个数组分别存储每个位置左侧和右侧的最大值
  3. 双指针优化:使用左右指针从两端向中间移动,动态更新左右最大值
  4. 单调栈:使用栈维护递减序列,遇到高柱子时计算水量
  5. 边界处理:位置0和n-1不能接水,因为至少需要两侧都有柱子

3 算法设计与实现

3.1 动态规划法(基础解法)

核心思想

预先计算每个位置左侧的最大值和右侧的最大值,存储在数组中,然后一次性计算所有位置的雨水量。

算法思路

  1. 创建左右最大值数组
    • leftMax[i] 表示位置 i 左侧(包括自身)的最大高度
    • rightMax[i] 表示位置 i 右侧(包括自身)的最大高度
  2. 计算左侧最大值
    • 从左到右遍历数组,leftMax[i] = max(leftMax[i-1], height[i])
  3. 计算右侧最大值
    • 从右到左遍历数组,rightMax[i] = max(rightMax[i+1], height[i])
  4. 计算总雨水量
    • 遍历每个位置 i,水量 = min(leftMax[i], rightMax[i]) - height[i]
    • 只累加正数结果

正确性证明

对于任意位置 i,其能接的雨水量取决于:

  1. 左侧最高柱子:确保左侧有边界
  2. 右侧最高柱子:确保右侧有边界
  3. 当前柱子高度:决定凹陷深度

通过预先计算左右最大值,我们可以在O(1)时间内得到每个位置的左右边界,从而正确计算雨水量。

代码实现

java 复制代码
public class TrappingRainWaterDP {
    public int trap(int[] height) {
        if (height == null || height.length < 3) {
            return 0;
        }
        
        int n = height.length;
        int total = 0;
        
        // 存储每个位置左侧的最大高度
        int[] leftMax = new int[n];
        leftMax[0] = height[0];
        for (int i = 1; i < n; i++) {
            leftMax[i] = Math.max(leftMax[i - 1], height[i]);
        }
        
        // 存储每个位置右侧的最大高度
        int[] rightMax = new int[n];
        rightMax[n - 1] = height[n - 1];
        for (int i = n - 2; i >= 0; i--) {
            rightMax[i] = Math.max(rightMax[i + 1], height[i]);
        }
        
        // 计算每个位置的雨水量
        for (int i = 1; i < n - 1; i++) {
            int water = Math.min(leftMax[i], rightMax[i]) - height[i];
            if (water > 0) {
                total += water;
            }
        }
        
        return total;
    }
}

优化版本(合并循环)

java 复制代码
public class TrappingRainWaterDPOptimized {
    public int trap(int[] height) {
        if (height == null || height.length < 3) return 0;
        
        int n = height.length;
        int total = 0;
        
        int[] leftMax = new int[n];
        int[] rightMax = new int[n];
        
        // 初始化左右最大值
        leftMax[0] = height[0];
        rightMax[n - 1] = height[n - 1];
        
        // 同时计算左右最大值
        for (int i = 1, j = n - 2; i < n; i++, j--) {
            leftMax[i] = Math.max(leftMax[i - 1], height[i]);
            if (j >= 0) {
                rightMax[j] = Math.max(rightMax[j + 1], height[j]);
            }
        }
        
        // 计算总雨水量
        for (int i = 1; i < n - 1; i++) {
            total += Math.min(leftMax[i], rightMax[i]) - height[i];
        }
        
        return total;
    }
}

3.2 双指针法

核心思想

使用左右两个指针从两端向中间移动,实时维护左侧最大值和右侧最大值。由于水量取决于较小的最大值,所以可以动态决定计算哪一边的水量。

算法思路

  1. 初始化指针和最大值
    • 左指针 left = 0,右指针 right = n-1
    • 左侧最大值 leftMax = height[0]
    • 右侧最大值 rightMax = height[n-1]
  2. 循环移动指针
    • left < right 时继续循环
    • 比较 leftMaxrightMax
      • 如果 leftMax < rightMax:处理左指针
        • 左指针右移:left++
        • 更新左侧最大值:leftMax = max(leftMax, height[left])
        • 计算水量:total += leftMax - height[left]
      • 否则:处理右指针
        • 右指针左移:right--
        • 更新右侧最大值:rightMax = max(rightMax, height[right])
        • 计算水量:total += rightMax - height[right]
  3. 返回结果:循环结束后返回总水量

正确性证明

关键问题:为什么总是移动较小最大值一侧的指针?

假设 leftMax < rightMax

  • 对于位置 left,其左侧最大值为 leftMax
  • 右侧最大值至少为 rightMax(因为 right 指针在右边)
  • 因此,位置 left 的水量受限于 leftMax
  • 可以安全地计算 left 位置的水量,然后移动左指针

同理,当 rightMax <= leftMax 时,可以安全地计算 right 位置的水量。

代码实现

java 复制代码
public class TrappingRainWaterTwoPointers {
    public int trap(int[] height) {
        if (height == null || height.length < 3) {
            return 0;
        }
        
        int left = 0;
        int right = height.length - 1;
        int leftMax = height[left];
        int rightMax = height[right];
        int total = 0;
        
        while (left < right) {
            // 总是移动较小最大值的一边
            if (leftMax < rightMax) {
                left++;
                leftMax = Math.max(leftMax, height[left]);
                total += leftMax - height[left];
            } else {
                right--;
                rightMax = Math.max(rightMax, height[right]);
                total += rightMax - height[right];
            }
        }
        
        return total;
    }
}

3.3 单调栈法

核心思想

使用栈存储柱子的索引,保持栈中元素对应的高度递减。当遇到一个比栈顶高的柱子时,说明形成了一个凹槽,可以接雨水。

算法思路

  1. 初始化栈:创建一个栈用于存储柱子的索引
  2. 遍历数组
    • 当栈非空且当前柱子高度大于栈顶柱子高度时:
      • 弹出栈顶元素作为凹槽底部
      • 如果栈为空,跳出循环
      • 计算凹槽宽度:当前索引 - 新栈顶索引 - 1
      • 计算凹槽高度:min(当前高度, 新栈顶高度) - 底部高度
      • 计算雨水量:宽度 × 高度
      • 累加到总水量
    • 将当前索引压入栈中
  3. 返回结果:遍历完成后返回总水量

正确性解释

单调栈法按层计算雨水量:

  1. 栈中存储的是递减的柱子高度索引
  2. 当遇到一个更高的柱子时,栈顶元素与当前柱子及新栈顶形成一个凹槽
  3. 计算这个凹槽能接的雨水量
  4. 这种方法特别适合处理复杂形状的雨水收集

代码实现

java 复制代码
import java.util.Stack;

public class TrappingRainWaterMonotonicStack {
    public int trap(int[] height) {
        if (height == null || height.length < 3) {
            return 0;
        }
        
        Stack<Integer> stack = new Stack<>();
        int total = 0;
        int n = height.length;
        
        for (int i = 0; i < n; i++) {
            // 当栈非空且当前高度大于栈顶高度时
            while (!stack.isEmpty() && height[i] > height[stack.peek()]) {
                // 弹出栈顶元素,作为凹槽的底部
                int bottom = stack.pop();
                
                // 如果栈为空,说明左边没有柱子,无法形成凹槽
                if (stack.isEmpty()) {
                    break;
                }
                
                // 计算凹槽宽度和高度
                int left = stack.peek();
                int distance = i - left - 1;
                int h = Math.min(height[i], height[left]) - height[bottom];
                
                // 累加雨水量
                total += distance * h;
            }
            
            // 将当前索引入栈
            stack.push(i);
        }
        
        return total;
    }
}

3.4 暴力枚举法

核心思想

对于数组中的每个元素,分别向左和向右扫描,找到左侧最大值和右侧最大值,然后计算该位置能接的雨水量。

算法思路

  1. 遍历每个位置:从索引1到n-2(两端不能接水)
  2. 向左扫描:找到当前位置左侧的最大高度
  3. 向右扫描:找到当前位置右侧的最大高度
  4. 计算雨水量:min(左最大, 右最大) - 当前高度
  5. 累加正数结果:如果结果为正,累加到总水量
  6. 返回结果:遍历完成后返回总水量

时间复杂度分析

  • 对于每个位置,需要向左向右扫描:O(n)
  • 共有n个位置:O(n²)
  • 不适用于大规模数据

代码实现

java 复制代码
public class TrappingRainWaterBruteForce {
    public int trap(int[] height) {
        if (height == null || height.length < 3) {
            return 0;
        }
        
        int n = height.length;
        int total = 0;
        
        // 遍历每个柱子(跳过第一个和最后一个)
        for (int i = 1; i < n - 1; i++) {
            // 找到左边最大高度
            int leftMax = 0;
            for (int j = i - 1; j >= 0; j--) {
                leftMax = Math.max(leftMax, height[j]);
            }
            
            // 找到右边最大高度
            int rightMax = 0;
            for (int j = i + 1; j < n; j++) {
                rightMax = Math.max(rightMax, height[j]);
            }
            
            // 计算当前柱子能接的雨水量
            int water = Math.min(leftMax, rightMax) - height[i];
            if (water > 0) {
                total += water;
            }
        }
        
        return total;
    }
}

3.5 双指针优化法

核心思想

在标准双指针法的基础上,优化条件判断和移动逻辑,减少不必要的计算,提高代码执行效率。

算法思路

  1. 初始化指针和最大值
    • 左指针 left = 0,右指针 right = n-1
    • 左侧最大值 leftMax = 0,右侧最大值 rightMax = 0
  2. 循环移动指针
    • left <= right 时继续循环
    • 更新左侧最大值:leftMax = max(leftMax, height[left])
    • 更新右侧最大值:rightMax = max(rightMax, height[right])
    • 如果 leftMax < rightMax
      • 计算左边水量:total += leftMax - height[left]
      • 左指针右移:left++
    • 否则:
      • 计算右边水量:total += rightMax - height[right]
      • 右指针左移:right--
  3. 返回结果:循环结束后返回总水量

优化点

  1. 提前更新最大值:在计算水量前先更新左右最大值
  2. 简化条件判断:直接比较左右最大值,逻辑更清晰
  3. 减少变量使用:使用更少的临时变量

代码实现

java 复制代码
public class TrappingRainWaterTwoPointersOptimized {
    public int trap(int[] height) {
        if (height == null || height.length < 3) {
            return 0;
        }
        
        int left = 0;
        int right = height.length - 1;
        int leftMax = 0;
        int rightMax = 0;
        int total = 0;
        
        while (left <= right) {
            // 更新左右最大值
            leftMax = Math.max(leftMax, height[left]);
            rightMax = Math.max(rightMax, height[right]);
            
            // 总是先处理较小最大值的一边
            if (leftMax < rightMax) {
                total += leftMax - height[left];
                left++;
            } else {
                total += rightMax - height[right];
                right--;
            }
        }
        
        return total;
    }
}

4 性能分析与对比

4.1 复杂度对比

方法 时间复杂度 空间复杂度 实现难度 优点 缺点
动态规划法 O(n) O(n) ★★☆☆☆ 思路清晰,易于理解 需要额外存储空间
双指针法 O(n) O(1) ★★★☆☆ 时间和空间都最优 逻辑稍复杂
单调栈法 O(n) O(n) ★★★☆☆ 可以处理复杂形状 空间占用大
暴力枚举法 O(n²) O(1) ★☆☆☆☆ 实现简单 效率低
双指针优化法 O(n) O(1) ★★★☆☆ 性能最优 条件判断需仔细

4.2 性能分析

  1. 时间复杂度

    • 暴力法在n=20000时不可行(约4亿次操作)
    • 其他方法在n=20000时都只需要约20000次操作
  2. 空间复杂度

    • 双指针法最优,只需常数空间
    • 动态规划和单调栈需要O(n)空间
  3. 实际性能

    • 在LeetCode测试中,双指针法通常最快(1-2ms)
    • 动态规划稍慢(2-3ms),因为需要额外数组
    • 单调栈最慢(3-5ms),因为涉及栈操作

4.3 正确性证明

双指针法的正确性可以通过以下方式证明:

假设在某一时刻,leftMax < rightMax

  • 对于位置 left,其左侧最大值为 leftMax
  • 其右侧最大值至少为 rightMax(因为右指针在右边)
  • 因此,位置 left 的水量由 leftMax 决定
  • 我们可以安全地计算 left 位置的水量,然后移动左指针

同理,当 rightMax <= leftMax 时,可以安全地计算 right 位置的水量。

选择建议

  • 面试场景:推荐动态规划或双指针法
  • 竞赛场景:双指针法,性能最优
  • 生产环境:根据数据规模和内存限制选择
  • 学习场景:从暴力法开始,逐步理解优化思路

5.边界情况处理

5.1 常见边界情况

  1. 数组长度小于3:无法形成凹槽,直接返回0
  2. 全零数组:所有高度为0,无法接水,返回0
  3. 递增或递减序列:无法形成凹槽,返回0
  4. 单元素或空数组:无法接水,返回0
  5. 中间有零:零高度的柱子也可以接水,取决于左右边界
  6. 相邻柱子等高:不会形成凹槽,但可能会影响后续计算

5.2 边界处理技巧

  1. 输入验证:方法开头检查数组长度,小于3直接返回0
  2. 指针边界:双指针法中,确保指针移动时不会越界
  3. 栈空检查:单调栈法中,弹出元素后检查栈是否为空
  4. 负数处理:题目限定高度为非负整数,无需处理负数
  5. 整数溢出 :最大水量可能达到10^5 × 2×10^4 = 2×10^9,在int范围内,但使用long更安全

6.扩展与变体

6.1 二维接雨水问题

在二维矩阵中接雨水,每个格子有高度,雨水可以在四个方向流动。

java 复制代码
public class TrappingRainWater2D {
    // 这是一个更复杂的问题,通常使用优先队列(最小堆)解决
    // 从边界开始,使用BFS或DFS向内部扩展
    public int trapRainWater(int[][] heightMap) {
        if (heightMap == null || heightMap.length < 3 || heightMap[0].length < 3) {
            return 0;
        }
        
        int m = heightMap.length;
        int n = heightMap[0].length;
        boolean[][] visited = new boolean[m][n];
        PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[2] - b[2]);
        
        // 将边界加入优先队列
        for (int i = 0; i < m; i++) {
            pq.offer(new int[]{i, 0, heightMap[i][0]});
            pq.offer(new int[]{i, n - 1, heightMap[i][n - 1]});
            visited[i][0] = true;
            visited[i][n - 1] = true;
        }
        
        for (int j = 1; j < n - 1; j++) {
            pq.offer(new int[]{0, j, heightMap[0][j]});
            pq.offer(new int[]{m - 1, j, heightMap[m - 1][j]});
            visited[0][j] = true;
            visited[m - 1][j] = true;
        }
        
        int total = 0;
        int[][] dirs = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
        
        while (!pq.isEmpty()) {
            int[] cell = pq.poll();
            int x = cell[0], y = cell[1], h = cell[2];
            
            for (int[] dir : dirs) {
                int nx = x + dir[0];
                int ny = y + dir[1];
                
                if (nx >= 0 && nx < m && ny >= 0 && ny < n && !visited[nx][ny]) {
                    visited[nx][ny] = true;
                    total += Math.max(0, h - heightMap[nx][ny]);
                    pq.offer(new int[]{nx, ny, Math.max(h, heightMap[nx][ny])});
                }
            }
        }
        
        return total;
    }
}

6.2 最多接雨水问题

在可以移除k个柱子的情况下,求最多能接多少雨水。

java 复制代码
public class TrappingRainWaterWithRemoval {
    /**
     * 允许移除k个柱子,求最大接雨水量
     * 这是一个更复杂的问题,可能需要动态规划
     */
    public int trapWithRemoval(int[] height, int k) {
        // 简化思路:尝试移除不同的柱子,计算最大接水量
        // 实际需要更复杂的动态规划解法
        int maxWater = 0;
        int n = height.length;
        
        // 暴力尝试所有可能的移除组合(仅适用于小k)
        // 这里只是示意,实际需要优化
        for (int mask = 0; mask < (1 << n); mask++) {
            if (Integer.bitCount(mask) != k) continue;
            
            // 创建移除后的新数组
            List<Integer> newHeight = new ArrayList<>();
            for (int i = 0; i < n; i++) {
                if ((mask & (1 << i)) == 0) {
                    newHeight.add(height[i]);
                }
            }
            
            // 计算接水量
            int water = new TrappingRainWaterTwoPointers().trap(
                newHeight.stream().mapToInt(i -> i).toArray());
            maxWater = Math.max(maxWater, water);
        }
        
        return maxWater;
    }
}

6.3 接雨水II(有渗透问题)

考虑雨水可以从底部渗透,或者柱子有渗透率。

java 复制代码
public class TrappingRainWaterWithPermeability {
    /**
     * 考虑柱子有渗透率,部分水会渗透
     * 渗透率数组permeability,表示每个柱子的渗透比例
     */
    public int trapWithPermeability(int[] height, double[] permeability) {
        if (height == null || height.length < 3) return 0;
        
        int n = height.length;
        int total = 0;
        
        int[] leftMax = new int[n];
        int[] rightMax = new int[n];
        
        leftMax[0] = height[0];
        for (int i = 1; i < n; i++) {
            leftMax[i] = Math.max(leftMax[i - 1], height[i]);
        }
        
        rightMax[n - 1] = height[n - 1];
        for (int i = n - 2; i >= 0; i--) {
            rightMax[i] = Math.max(rightMax[i + 1], height[i]);
        }
        
        // 计算考虑渗透的雨水量
        for (int i = 1; i < n - 1; i++) {
            int water = Math.min(leftMax[i], rightMax[i]) - height[i];
            if (water > 0) {
                // 考虑渗透,实际接水量减少
                double actualWater = water * (1 - permeability[i]);
                total += (int) actualWater;
            }
        }
        
        return total;
    }
}

6.4 实时接雨水监控

支持动态添加新的柱子,并实时更新接雨水量。

java 复制代码
public class DynamicTrappingRainWater {
    private List<Integer> heights = new ArrayList<>();
    private int totalWater = 0;
    
    public void addHeight(int h) {
        heights.add(h);
        updateWater();
    }
    
    private void updateWater() {
        // 重新计算总接水量
        int[] arr = heights.stream().mapToInt(i -> i).toArray();
        totalWater = new TrappingRainWaterTwoPointers().trap(arr);
    }
    
    public int getTotalWater() {
        return totalWater;
    }
    
    // 优化版本:增量更新
    public void addHeightOptimized(int h) {
        heights.add(h);
        int n = heights.size();
        
        if (n < 3) return;
        
        // 简化增量更新:只重新计算受影响的部分
        // 实际实现更复杂,这里只是示意
        updateWater(); // 实际应用中需要更精细的更新逻辑
    }
}

7.总结

7.1 核心知识点总结

  1. 木桶原理:每个位置的水量取决于左右两边最高柱子的较小值
  2. 预处理思想:动态规划通过预处理数组避免重复计算
  3. 双指针技巧:从两端向中间扫描,实时更新左右最大值
  4. 单调栈应用:利用栈维护递减序列,处理凹槽问题
  5. 空间优化:双指针法在O(1)空间内解决问题

7.2 算法思维提升

  1. 问题转化能力:将接雨水问题转化为求每个位置的左右最大值问题
  2. 优化思维:从暴力法O(n²)到动态规划O(n),再到双指针O(1)空间的优化过程
  3. 数据结构应用:单调栈在处理凹槽类问题中的应用
  4. 边界思维:考虑各种极端情况,确保算法健壮性

7.3 实际应用场景

  1. 城市规划:计算城市地表雨水收集能力
  2. 水利工程:设计水库、水坝的容量计算
  3. 图像处理:处理图像中的低洼区域
  4. 游戏开发:地形生成中的水位计算
  5. 数据分析:时间序列中的低谷填充

7.4 面试建议

  1. 首选解法:动态规划或双指针法,根据面试官要求选择
  2. 解题步骤
    • 分析问题本质:水量 = min(左最大, 右最大) - 当前高度
    • 提出暴力解法:对每个位置向左右扫描
    • 优化思路:预处理左右最大值数组(动态规划)
    • 进一步优化:双指针法减少空间使用
    • 扩展思路:单调栈处理复杂形状
相关推荐
AlenTech16 小时前
739. 每日温度 - 力扣(LeetCode)
算法·leetcode·职场和发展
老鼠只爱大米16 小时前
LeetCode算法题详解 11:盛最多水的容器
leetcode·面试题·双指针·盛最多水的容器·面积最大化
im_AMBER19 小时前
Leetcode 99 删除排序链表中的重复元素 | 合并两个链表
数据结构·笔记·学习·算法·leetcode·链表
源代码•宸20 小时前
Leetcode—1123. 最深叶节点的最近公共祖先【中等】
经验分享·算法·leetcode·职场和发展·golang·dfs
alphaTao20 小时前
LeetCode 每日一题 2026/1/5-2026/1/11
算法·leetcode
黎雁·泠崖20 小时前
二叉树知识体系全梳理:从基础到进阶一站式通关
c语言·数据结构·leetcode
Cx330❀21 小时前
【优选算法必刷100题】第43题(模拟):数青蛙
c++·算法·leetcode·面试
闻缺陷则喜何志丹21 小时前
【C++动态规划 状压dp】1879. 两个数组最小的异或值之和|2145
c++·算法·动态规划·力扣·数组·最小·动态规范
妹妹够啦21 小时前
1. 两数之和
数据结构·算法·leetcode