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(左边最高, 右边最高) - heighti(如果结果为正)

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(左最大, 右最大) - 当前高度
    • 提出暴力解法:对每个位置向左右扫描
    • 优化思路:预处理左右最大值数组(动态规划)
    • 进一步优化:双指针法减少空间使用
    • 扩展思路:单调栈处理复杂形状
相关推荐
风筝在晴天搁浅8 小时前
美团 LeetCode 692.前K个高频单词
算法·leetcode·职场和发展
z200509309 小时前
今日算法(回溯子集)(模版题)
数据结构·算法·leetcode
YL2004042610 小时前
071字符串解码
数据结构·leetcode
z2005093013 小时前
今日算法(回溯子集)
数据结构·算法·leetcode
Hesionberger13 小时前
巧用异或找出唯一数字(多解)
java·数据结构·python·算法·leetcode
菜菜的顾清寒13 小时前
力扣HOT100(47) 二叉树的层序遍历
算法·leetcode·深度优先
sheeta199814 小时前
LeetCode 每日一题笔记 日期:2026.05.31 题目:2126. 摧毁小行星
笔记·算法·leetcode
INGNIGHT14 小时前
984.不含 AAA 或 BBB 的字符串(贪心)
开发语言·算法·leetcode
散峰而望15 小时前
【算法练习】算法练习精选:从 Phone numbers 到 Decrease,覆盖字符串、模拟、图论思维题
数据结构·c++·算法·贪心算法·github·动态规划·图论
人道领域15 小时前
【LeetCode刷题日记】538.把二叉搜索树转换为累加树
java·开发语言·后端·算法·leetcode