力扣接雨水题c++和c#思路及代码

题目:给定 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

这里先提供我c++时的第一种思路,后面运行时会超时

一、这是一种暴力解法对每个柱子,计算其左右两侧最高柱子的高度,然后根据这两侧的最低高度与当前柱子的高度差,计算该柱子能接的雨水量

  1. 问题核心
    每个柱子能接的雨水量取决于其左右两侧的最高柱子。具体来说,当前柱子height[i]能接的雨水量为:

    雨水量=min⁡(左最大高度,右最大高度)−当前高度(若结果为正)雨水量=min(左最大高度,右最大高度)−当前高度(若结果为正)

    如果左/右最大高度中至少有一个不超过当前高度,则无法接水。

  2. 暴力解法的步骤

    • 遍历每个柱子i(首尾柱子无法接水,因此遍历范围为i = 1i = n-2)。
  3. 对每个柱子i
    1. 向左遍历:找到左侧所有柱子中的最大高度leftMax
    2. 向右遍历:找到右侧所有柱子中的最大高度rightMax
    3. 如果leftMaxrightMax中至少有一个不超过height[i],则跳过(无法接水)。
    4. 否则,计算当前柱子能接的雨水量:min(leftMax, rightMax) - height[i],并累加到总和中。
    class Solution 
    {
    public:
        int trap(vector<int>& height) 
        {
            int n = height.size();
            int total = 0;
            for(int i = 1;i < n-1;i++)
            {
                int leftMax = 0;
                int rightMax = 0;
                for(int j = i-1;j >= 0;j--)
                {
                    leftMax = max(leftMax,height[j]);
                }
                for(int j = i+1;j < n;j++)
                {
                    rightMax = max(rightMax,height[j]);
                }
    
                if(leftMax <= height[i] || rightMax <= height[i])
                {
                    continue;
                }
    
                total += min(leftMax,rightMax) - height[i];
            }
            return total;
        }
    };

     

  • 时间复杂度:O(n2)O(n2)
    对于每个柱子i,需要两次线性遍历(左遍历和右遍历),总时间复杂度为 O(n×n)=O(n2)O(n×n)=O(n2)。

  • 空间复杂度:O(1)O(1)
    仅使用了常数额外空间(leftMaxrightMaxtotal等变量)。

二、双指针法

通过维护左右两个指针和左右两侧的最大高度,动态计算每个位置能接的雨水量。具体步骤如下:

  1. 初始化指针和变量

    • left 指针从左向右移动(初始位置为 1)。
    • right 指针从右向左移动(初始位置为 n-2)。
    • maxLeftHeight 记录左侧已遍历的最大高度(初始为 height[0])。
    • maxRightHeight 记录右侧已遍历的最大高度(初始为 height[n-1])。
  2. 循环条件

    • 当 left <= right 时,指针持续向中间移动,直到相遇。
  3. 移动指针的策略

    • 比较左右最大高度:若 maxLeftHeight < maxRightHeight,则当前左侧的指针位置的雨水量由 maxLeftHeight 决定,因此移动 left 指针向右。
    • 否则(maxLeftHeight >= maxRightHeight),当前右侧的指针位置的雨水量由 maxRightHeight 决定,因此移动 right 指针向左。
  4. 计算雨水量

    • 当移动左指针时
      • 如果当前高度 height[left] 小于 maxLeftHeight,则该位置能接的雨水量为 maxLeftHeight - height[left]
      • 否则,更新 maxLeftHeight 为当前高度 height[left]
    • 当移动右指针时
      • 如果当前高度 height[right] 小于 maxRightHeight,则该位置能接的雨水量为 maxRightHeight - height[right]
      • 否则,更新 maxRightHeight 为当前高度 height[right]

c++部分

class Solution 
{
public:
    int trap(vector<int>& height) 
    {
        int n = height.size();
        int total = 0;
        int left = 1,right = n-2;
        int maxLeftHeight = height[0];
        int maxRightHeight = height[n-1];
        while(left <= right)
        {
            if(maxLeftHeight < maxRightHeight)
            {
                if(maxLeftHeight > height[left])
                {
                    total += (maxLeftHeight - height[left]);
                }
                else
                {
                    maxLeftHeight = height[left];
                }
                left++;
            }
            else
            {
                if(maxRightHeight > height[right])
                {
                    total += (maxRightHeight - height[right]);
                }
                else
                {
                    maxRightHeight = height[right];
                }
                right--;
            }
        }
        return total;
    }
};

c#部分

public class Solution 
{
    public int Trap(int[] height) 
    {
        int n = height.Length;
        int total = 0;
        int left = 1,right = n-2;
        int maxLeftHeight = height[0];
        int maxRightHeight = height[n-1];
        while(left <= right)
        {
            if(maxLeftHeight < maxRightHeight)
            {
                if(maxLeftHeight > height[left])
                {
                    total += (maxLeftHeight - height[left]);
                }
                else
                {
                    maxLeftHeight = height[left];
                }
                left++;
            }
            else
            {
                if(maxRightHeight > height[right])
                {
                    total += (maxRightHeight - height[right]);
                }
                else
                {
                    maxRightHeight = height[right];
                }
                right--;
            }
        }
        return total;
    }
}
  • 时间复杂度:O(n)O(n)
    每个柱子仅被访问一次,指针从两端向中间移动,总循环次数为 n−2n−2(排除首尾)。

  • 空间复杂度:O(1)O(1)
    仅使用了常数额外空间(指针和临时变量)。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

变身缎带

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值