Hard!

题目描述:

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。

示例:

输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6

解题思路:

先来看一种方法,这种方法是基于动态规划Dynamic Programming的,我们维护一个一维的dp数组,这个DP算法需要遍历两遍数组,第一遍遍历dp[i]中存入i位置左边的最大值,然后开始第二遍遍历数组,第二次遍历时找右边最大值,然后和左边最大值比较取其中的较小值,然后跟当前值A[i]相比,如果大于当前值,则将差值存入结果。

C++解法一:

 class Solution {
public:
int trap(vector<int>& height) {
int res = , mx = , n = height.size();
vector<int> dp(n, );
for (int i = ; i < n; ++i) {
dp[i] = mx;
mx = max(mx, height[i]);
}
mx = ;
for (int i = n - ; i >= ; --i) {
dp[i] = min(dp[i], mx);
mx = max(mx, height[i]);
if (dp[i] > height[i]) res += dp[i] - height[i];
}
return res;
}
};

最后我们来看一种只需要遍历一次即可的解法,这个算法需要left和right两个指针分别指向数组的首尾位置,从两边向中间扫描,在当前两指针确定的范围内,先比较两头找出较小值,如果较小值是left指向的值,则从左向右扫描,如果较小值是right指向的值,则从右向左扫描,若遇到的值比当前较小值小,则将差值存入结果,如遇到的值大,则重新确定新的窗口范围,以此类推直至left和right指针重合。

C++解法二:

 class Solution {
public:
int trap(vector<int>& height) {
int res = , l = , r = height.size() - ;
while (l < r) {
int mn = min(height[l], height[r]);
if (mn == height[l]) {
++l;
while (l < r && height[l] < mn) {
res += mn - height[l++];
}
} else {
--r;
while (l < r && height[r] < mn) {
res += mn - height[r--];
}
}
}
return res;
}
};

我们可以对上面的解法进行进一步优化,使其更加简洁。

C++解法三:

 class Solution {
public:
int trap(vector<int>& height) {
int l = , r = height.size() - , level = , res = ;
while (l < r) {
int lower = height[(height[l] < height[r]) ? l++ : r--];
level = max(level, lower);
res += level - lower;
}
return res;
}
};

下面这种解法是用stack来做的。其实用stack的方法更容易理解,我们的做法是,遍历高度,如果此时栈为空,或者当前高度小于等于栈顶高度,则把当前高度的坐标压入栈,注意我们不直接把高度压入栈,而是把坐标压入栈,这样方便我们接下来计算水平距离。

当我们遇到比栈顶高度高的时候,就说明有可能会有坑存在,可以装雨水。此时我们栈里至少有一个高度,如果只有一个的话,那么不能形成坑,我们直接跳过,如果多于一个的话,那么此时把栈顶元素取出来当作坑,新的栈顶元素就是左边界,当前高度是右边界,只要取二者较小的,减去坑的高度,长度就是右边界坐标减去左边界坐标再减1,二者相乘就是盛水量了。

C++解法四:

 class Solution {
public:
int trap(vector<int>& height) {
stack<int> st;
int i = , res = , n = height.size();
while (i < n) {
if (st.empty() || height[i] <= height[st.top()]) {
st.push(i++);
} else {
int t = st.top(); st.pop();
if (st.empty()) continue;
res += (min(height[i], height[st.top()]) - height[t]) * (i - st.top() - );
}
}
return res;
}
};

LeetCode(42):接雨水的更多相关文章

  1. Java实现 LeetCode 42 接雨水

    42. 接雨水 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水. 上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这 ...

  2. [LeetCode]42. 接雨水(双指针,DP)

    题目 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水. 上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下, ...

  3. leetcode 42. 接雨水 JAVA

    题目: 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水. 上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下 ...

  4. Leetcode 42.接雨水

    接雨水 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水. 上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下 ...

  5. Leetcode 42 接雨水 双指针

    地址 https://leetcode-cn.com/problems/trapping-rain-water/ 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能 ...

  6. LeetCode 42. 接雨水(Trapping Rain Water)

    题目描述 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水. 上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况 ...

  7. LeetCode(42.接雨水)多解法详解

    接雨水解法详解: 题目: 基本思路:从图上可以看出要想接住雨水,必须是凹字形的,也就是当前位置的左右两边必须存在高度大于它的地方,所以我们要想知道当前位置最多能存储多少水,只需找到左边最高处max_l ...

  8. LeetCode 42接雨水 按行求解(差分+排序)

    按行求解的思路比较清晰明了,但是这个方法的复杂度高达O(heightSize*sum(height[i])),几乎高达O(N^2). 但是也并不是不可以解决,经观察我们可以发现,这个算法的缺点在于要遍 ...

  9. 每日一题 LeetCode 42.接雨水 【双指针】

    题目链接 https://leetcode-cn.com/problems/trapping-rain-water/ 题目说明 题解 主要方法:双指针 + 正反遍历 解释说明: 正向遍历:先确定池子左 ...

  10. LeetCode:接雨水【42】

    LeetCode:接雨水[42] 题目描述 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水. 上面是由数组 [0,1,0,2,1,0,1,3,2,1, ...

随机推荐

  1. 20145215《网络对抗》Exp9 Web安全基础实践

    20145215<网络对抗>Exp9 Web安全基础实践 基础问题回答 SQL注入攻击原理,如何防御? SQL注入攻击就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符 ...

  2. 即将上线的flume服务器面临的一系列填坑笔记

      即将上线的flume服务器面临的一系列填坑笔记 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.   一.flume缺少依赖包导致启动失败! 报错信息如下: 2018-10-17 ...

  3. 面向对象【day07】:类的属性(五)

    本节内容 概述 公有属性 一.概述 前面我们讲了类的私有属性,现在我们来说说类的公有属性,这边很容易被人弄混淆,有人觉的,在__init__()构造方法中,除了私有属性,其他的都是公有属性了,其实这是 ...

  4. python---RabbitMQ(1)简单队列使用,消息依次分发(一对一),消息持久化处理

    MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法.应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们.消息传递指的是程序之间 ...

  5. java的递归查询大体思路

    场景:递归查询是我们开发中很常见的,如果没有一个比较好的思路,这将会让我们很头疼. 我这里介绍一个查询部门的例子,希望能给你一些启发 部门sql -- ------------------------ ...

  6. JAVA记录-redis缓存机制介绍(三)

    Redis 事务 Redis 事务可以一次执行多个命令, 并且带有以下两个重要的保证: 事务是一个单独的隔离操作:事务中的所有命令都会序列化.按顺序地执行.事务在执行的过程中,不会被其他客户端发送来的 ...

  7. IDEA中设置Tab多行显示、打开过多自动关闭的方法

    IDEA中默认Tab是单行显示的,而且默认允许同时打开10个Tab,继续打开Tab会根据规则关闭之前打开的Tab.但是可以通过设置来符合自己的使用习惯. 一.打开Tab过多自动关闭 1.选择File→ ...

  8. PHP7 学习笔记(八)JetBrains PhpStorm 2017.1 x64 MySQL数据库管理工具的使用

    填写基本信息 这时候我们可以看到已经连接成功的数据库了 打开一个表,我们可以很清楚的看到数据库表的数据 切换到DDL模式

  9. 正方体旋转demo

    接着上一篇博客的内容顺藤摸瓜往下想,既然stage有景深这个概念,可以表达3D场景,那么这个stage就可以呈现立体几何咯,于是自己写了个Cubic Demo 一个正方体有6个面,我们把一个正方体平铺 ...

  10. pd.qcut, pd.cut, df.groupby()等在分组和聚合方面的应用

    pd.qcut, pd.cut, df.groupby()等在分组和聚合方面的应用 量化交易里, 需要进行大量的分组和统计, 以方便自己处优势的位置/机会. 比如对股价进行趋势分析, 波动性分析, 量 ...