力扣第四十二题——接雨水

内容介绍

给定 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 * 104
  • 0 <= height[i] <= 105

完整代码

 int trap(int* height, int heightSize) {
    int n = heightSize;
    if (n == 0) {
        return 0;
    }
    int leftMax[n];
    memset(leftMax, 0, sizeof(leftMax));
    leftMax[0] = height[0];
    for (int i = 1; i < n; ++i) {
        leftMax[i] = fmax(leftMax[i - 1], height[i]);
    }

    int rightMax[n];
    memset(rightMax, 0, sizeof(rightMax));
    rightMax[n - 1] = height[n - 1];
    for (int i = n - 2; i >= 0; --i) {
        rightMax[i] = fmax(rightMax[i + 1], height[i]);
    }

    int ans = 0;
    for (int i = 0; i < n; ++i) {
        ans += fmin(leftMax[i], rightMax[i]) - height[i];
    }
    return ans;
}

思路详解

解题思路

这个问题可以通过计算每个柱子上方可以积累的水量来解决。对于每个柱子,它上方可以积累的水量取决于它左边最高的柱子和右边最高的柱子中的较小者。

步骤分解
  1. 初始化辅助数组

    • leftMax:一个数组,用来存储从左到右每个位置左侧的最高柱子高度。
    • rightMax:一个数组,用来存储从右到左每个位置右侧的最高柱子高度。
  2. 填充 leftMax 数组

    • 遍历 height 数组,对于每个位置 ileftMax[i] 应该是 leftMax[i-1] 和 height[i] 中的较大者。这意味着 leftMax[i] 存储了位置 i 左侧(包括 i)最高的柱子高度。
  3. 填充 rightMax 数组

    • 从右向左遍历 height 数组,对于每个位置 irightMax[i] 应该是 rightMax[i+1] 和 height[i] 中的较大者。这意味着 rightMax[i] 存储了位置 i 右侧(包括 i)最高的柱子高度。
  4. 计算水量

    • 对于每个位置 i,它能积累的水量等于 min(leftMax[i], rightMax[i]) - height[i]。这是因为水会被左侧和右侧最高柱子中的较小者限制。
    • 将每个位置的水量累加,得到总的积水量。
代码详解
int trap(int* height, int heightSize) {
    int n = heightSize;
    if (n == 0) {
        return 0; // 如果数组为空,则无法积水,直接返回0。
    }

    int leftMax[n];
    memset(leftMax, 0, sizeof(leftMax)); // 初始化leftMax数组。
    leftMax[0] = height[0]; // 第一个元素左侧没有更高的柱子,所以leftMax[0]等于height[0]。
    for (int i = 1; i < n; ++i) {
        leftMax[i] = fmax(leftMax[i - 1], height[i]); // 更新leftMax数组。
    }

    int rightMax[n];
    memset(rightMax, 0, sizeof(rightMax)); // 初始化rightMax数组。
    rightMax[n - 1] = height[n - 1]; // 最后一个元素右侧没有更高的柱子,所以rightMax[n-1]等于height[n-1]。
    for (int i = n - 2; i >= 0; --i) {
        rightMax[i] = fmax(rightMax[i + 1], height[i]); // 更新rightMax数组。
    }

    int ans = 0;
    for (int i = 0; i < n; ++i) {
        ans += fmin(leftMax[i], rightMax[i]) - height[i]; // 计算每个位置的水量并累加。
    }
    return ans; // 返回总的积水量。
}
总结

该算法首先通过两次遍历构建了两个辅助数组 leftMax 和 rightMax,然后在第三次遍历中计算并累加每个位置的水量。最终得到整个直方图容器可以积累的水量。这个算法的时间复杂度为 O(n),空间复杂度也为 O(n)。

知识点精炼

辅助数组的应用
  • 使用两个辅助数组 leftMax 和 rightMax 来存储每个位置左侧和右侧的最大高度。
2. 动态规划思想
  • 通过遍历直方图数组,动态更新 leftMax 和 rightMax,体现了动态规划中“状态转移”的概念。
3. 边界条件处理
  • 对于 leftMax 的第一个元素和 rightMax 的最后一个元素,它们没有左侧或右侧的元素,因此直接赋值为对应的高度。
4. 数组初始化
  • 使用 memset 函数初始化辅助数组,确保数组的初始状态是已知的。
5. 最大值与最小值计算
  • 使用 fmax 和 fmin 函数来计算两个值中的最大值和最小值,分别用于更新辅助数组和计算水量。
6. 累加求和
  • 通过一个循环遍历直方图数组,计算每个位置可以积累的水量并累加到总水量中。
7. 空间复杂度与时间复杂度
  • 算法的时间复杂度为 O(n),因为涉及三个独立的遍历操作。
  • 空间复杂度也为 O(n),由于使用了两个额外的数组来存储最大高度信息。
8. 特殊情况处理
  • 在数组为空时,直接返回 0,处理了边界情况。

 

  • 13
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值