【LeetCode 42】接雨水(单调栈、DP、双指针)

题面:

思路:

能接雨水的点,必然是比两边都低(小)的点。有两种思路,一种是直接计算每个点的最大贡献(也就是每个点在纵向上最多能接多少水),另一种就是计算每个点在横向上有没有贡献。

第一种思路,就需要我们能拿到每个点左右两边最高的高度,这样就能计算每个点在纵向上能接多少水,相当于木桶效应。

第二种思路,对于每个点,则需要判断它左右两边是不是都有比它高的点,每次计算横向上局部能接到水的区域。
官方题解挺好的,具体不再赘述

1. 单调栈

就是第二种思路,每次更新横向上能接到的水。

cpp 复制代码
int trap(vector<int>& height) {
    int ans = 0, n = (int)height.size();
    stack<int> stk;
    for(int i = 0; i < n; ++ i) {
        while(!stk.empty() && height[i] > height[stk.top()]) {
        	// 得到当前低点
            int buttom = stk.top(); stk.pop();
            if(!stk.empty()) {
                int j = stk.top();
                // 如果 height[j] == height[bottom]
                // 就说明 bottom 的左边还没有出现凸出来让bottom能接到水的边边
                ans += (i - j - 1) * (min(height[i], height[j]) - height[buttom]);
            }
        }
        stk.push(i);
    }
    return ans;
}

2. 动态规划

第一种思路,要拿到每个点左右两边的最大高度,就可以考虑线性DP的思想去记录当前点左右两边的最大高度。
l e f t M a x i = m a x ( l e f t M a x i − 1 , h e i g h t i ) r i g h t M a x i = m a x ( r i g h t M a x i + 1 , h e i g h t i ) g o t W a t e r i = m i n ( l e f t M a x i , r i g h t M a x i ) − h e i g h t i leftMaxi=max(leftMaxi-1,heighti)\\ rightMaxi=max(rightMaxi+1,heighti)\\ gotWateri = min(leftMaxi,\ rightMaxi)-heighti leftMaxi=max(leftMaxi−1,heighti)rightMaxi=max(rightMaxi+1,heighti)gotWateri=min(leftMaxi, rightMaxi)−heighti

cpp 复制代码
int trap(vector<int>& height) {
    int ans = 0, n = (int)height.size();
    vector<int> leftMax(n), rightMax(n);
    leftMax[0] = height[0]; rightMax[n - 1] = height[n - 1];
    for(int i = 1; i < n; ++ i) leftMax[i] = max(leftMax[i - 1], height[i]);
    for(int i = n - 2; i >= 0; -- i) rightMax[i] = max(rightMax[i + 1], height[i]);

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

双指针

使用双指针和临时变量优化掉 l e f t M a x leftMax leftMax 和 r i g h t M a x rightMax rightMax 两个数组。

官方题解说:如果 h e i g h t l e f t < h e i g h t r i g h t heightleft<heightright heightleft<heightright,则必有 l e f t M a x < r i g h t M a x leftMax<rightMax leftMax<rightMax。

这主要是因为,我们每次移动的都是 h e i g h t height height 较小的指针,因此如果 l e f t M a x leftMax leftMax 或 r i g h t M a x rightMax rightMax 有更新,则更新了的点 l e f t left left 或 r i g h t right right 在 l e f t M a x leftMax leftMax 或 r i g h t M a x rightMax rightMax 得到新的更新之前会停留一阵子。因此如果 h e i g h t l e f t < h e i g h t r i g h t heightleft<heightright heightleft<heightright,则必有 l e f t M a x < r i g h t M a x leftMax<rightMax leftMax<rightMax。

cpp 复制代码
int trap(vector<int>& height) {
    int ans = 0, n = (int)height.size();
    int left = 0, right = n - 1;
    int leftMax = height[0], rightMax = height[n - 1];
    while(left < right) {
        leftMax = max(leftMax, height[left]);
        rightMax = max(rightMax, height[right]);
        if(height[left] < height[right])
            ans += min(leftMax, rightMax) - height[left ++];
        else
            ans += min(leftMax, rightMax) - height[right --];
    }
    return ans;
}
相关推荐
月疯19 小时前
PPG研究中暑的算法记录
算法
春日见20 小时前
vscode的AI编程插件推荐:
大数据·ide·vscode·算法·机器学习·编辑器·ai编程
blxr_20 小时前
力扣hot100路径总和Ⅲhttps://leetcode.cn/problems/path-sum-iii/
算法·leetcode·职场和发展
noipp20 小时前
【无标题】
c语言·数据结构·c++·算法
渡众机器人20 小时前
第八届全球校园人工智能算法精英大赛-算法应用赛-渡众机器人智能体对抗挑战赛规则
人工智能·算法·机器人·自动驾驶·自主导航·对抗赛
郝学胜-神的一滴21 小时前
完全二叉树与堆底层原理深度剖析 | 手写C++大顶堆实现
java·开发语言·数据结构·c++·python·算法
青山木21 小时前
Hot 100 --- 缺失的第一个正数
算法·leetcode·哈希算法
农民小飞侠21 小时前
[leetcode] 165. Compare Version Numbers
java·算法·leetcode
装不满的克莱因瓶21 小时前
掌握语义分割经典模型 FCN——从像素分类到端到端分割的奠基之作
人工智能·python·深度学习·算法·机器学习·分类·数据挖掘
学计算机的计算基21 小时前
链表算法上篇:LeetCode 206/234/141/142/160/21 题解与易错点
java·笔记·算法·链表