[算法刷题打卡]Day8

本文介绍了LeetCode中一道面试经典题目——接雨水问题的三种解决方案:动态规划、双指针和单调栈。主要讨论了如何利用这些方法计算给定高度数组中可以接收到的雨水量。
摘要由CSDN通过智能技术生成
1、Leetcode-面试经典150题目16-42. 接雨水

思路:

方法1:动态规划

很显然,在第i个下标处,下雨量取决于左右两边的最大高度的最小值,而接水的量等于下雨量-heigth[i];

所以创建两个长度为n的leftMax和rightMax数组,正向遍历height得到leftMax数组各元素的值,再反向遍历得到rightMax的每个元素的值。

在得到数组leftMax和rightMax的每个元素值之后,那么第i处能接的雨水量等于min(leftMax[i],rigthMax[i])-height[i]

 图片来源:leecode

class Solution {
public:
    int trap(vector<int>& height) {
        int  n = height.size();
        if(n == 0){
            return 0;
        }
        vector<int> leftMax(n);
        leftMax[0] = height[0];
        for(int i = 1;i < n;++i){
            leftMax[i] = max(leftMax[i-1],height[i]);
        }
        vector<int> rightMax(n);
        rightMax[n-1] = height[n-1];
        for(int i = n-2;i>= 0;--i){
            rightMax[i] = max(rightMax[i + 1],height[i]);
        }

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

方法2:双指针:

1.由动态规划中的“下雨量取决于左右两边的最大高度的最小值,而接水的量等于下雨量-heigth[i];”得到启发,两个数组可以用双指针和两个变量来替代。

2.维护两个指针leftrigth

3.当两个指针没有相遇时,进行如下操作:

不断更新leftmax和rigthmax的值;

  • 如果当前height[left]<height[rigth],则一定有leftMax <rigthMax,下标left处的接水量就是leftMax-height[left],然后left指针继续前进
  • 如果height[left] >= height[rigth],则一定有leftMax >= rightMax,下标rigth处的接水量等于rightMax - height[right],rigth指针继续左移
class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        if (n <= 2) return 0; // 如果数组长度小于等于2,无法形成坑,直接返回0

        int left = 0, right = n - 1; // 左右指针
        int left_max = 0, right_max = 0; // 左右指针所指位置左右两侧的最大高度
        int count = 0; // 接水量

        while (left < right) {
            if (height[left] < height[right]) { // 左侧低于右侧
                if (height[left] >= left_max) { // 当前位置高度大于左侧最大高度
                    left_max = height[left]; // 更新左侧最大高度
                } else { // 当前位置高度小于左侧最大高度,可以接水
                    count += left_max - height[left]; // 计算接水量
                }
                left++; // 左指针右移
            } else { // 右侧不低于左侧
                if (height[right] >= right_max) { // 当前位置高度大于右侧最大高度
                    right_max = height[right]; // 更新右侧最大高度
                } else { // 当前位置高度小于右侧最大高度,可以接水
                    count += right_max - height[right]; // 计算接水量
                }
                right--; // 右指针左移
            }
        }

        return count;
    }
};

方法3:单调栈 

1.还可以使用单调栈的方法,单调栈存储的是下标,满足从栈底到栈顶的下标对应的数组 height\textit{height}height 中的元素递减。

2.从左到右遍历数组,遍历到下标i时,如果栈内至少有两个元素,栈顶元素为top,top下面一个元素是left,如果heigth[left] >height[top],说明找到了一个接雨水的区域,区域宽度为i-left-1,高度是min(height[left],height[i])-height[top]

class Solution {
public:
    int trap(vector<int>& height) {
            int ans = 0;
            stack <int> stk;
            int n = height.size();
            for(int i = 0;i < n;++i){
                while(!stk.empty() && height[i] > height[stk.top()]){
                    int top = stk.top();
                    stk.pop();
                    if(stk.empty()){
                        break;
                    }
                    int left = stk.top();
                int currWidth = i-left-1;
                int currHeight = min(height[left],height[i])-height[top];
                ans += currWidth*currHeight;
                }
                stk.push(i);
            }
            return ans;
            
    }
};

知识点总结:数组、动态规划、双指针、单调栈


每日一言:成功的关键在于始终坚持追求目标的过程,而不是目标本身。

2024年4月1日

softdream

  • 18
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值