[C++]LeetCode: 131 Trapping Rain Water (双边扫描)
来源:互联网 发布:凯立德优化内存 编辑:程序博客网 时间:2024/06/05 14:46
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
For example,
Given [0,1,0,2,1,0,1,3,2,1,2,1]
, return 6
.
The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!
Answer 1:
思路:我们分析下这道题目,我们要得到每一个bar的储水量,需要知道它的左右最大高度,用比较小的高度(瓶颈,短板)和当前bar的高度做差得到储水量。第i块地方的存水量 = min(第i块左边最高的bar高度, 第i块右边最高的bar的高度) - 第i块地方bar的高度. 根据这个思路,我们需要进行两次扫描,分别得到每一个bar的左右最大高度。第一次扫描,从左往右,维护对于一个bar左边最大的高度是多少,存入数组对应元素;第二次扫描,从右往左,我们维护右边最大高度;然后同时,比较leftmax[i]和rightmax[i],取较小值为瓶颈存入数组对应元素。然后与当前bar做差,将大于0的值存入存水量。这样两次扫描后,就能得到每一个bar能承受的最大水量,从而累加得到结果。
复杂度:O(N), 空间需要一个长度为n的数组,复杂度也是O(N)
Attention:
1.max / min是c++的关键字,不能用来做变量名。
2.leftmax[0] = 0 ,左边是没有凭栏储水的。要先对数组赋值,再计算当前最大值(将当前bar的高度考虑进去)
<span style="font-size:14px;">//记录每一个bar左边最大高度 for(int i = 0; i < n; i++) { container[i] = maxheight; maxheight = max(maxheight, A[i]); }</span>3. 计算rightmax时,要重置maxheight.
<span style="font-size:14px;">maxheight = 0;</span>AC Code:
<span style="font-size:14px;">class Solution {public: int trap(int A[], int n) { int maxheight = 0; int ret = 0; vector<int> container(n, 0); //记录每一个bar左边最大高度 for(int i = 0; i < n; i++) { container[i] = maxheight; maxheight = max(maxheight, A[i]); } maxheight = 0; //记录每一个bar右边最大高度,并找到瓶颈,统计存水量 for(int i = n - 1; i >= 0; i--) { container[i] = min(maxheight, container[i]); maxheight = max(maxheight, A[i]); ret += container[i] - A[i] > 0 ? container[i] - A[i] : 0; } return ret; }};</span>
这个方法是一种常见技巧,从两边各扫描一次得到我们需要维护的变量,通常适用于当前元素需要两边元素来决定的问题,类似的题目还有candy.
Answer 2: 优化算法
思路:我们还是使用两个指针a和b, 每一次循环,我们更新左边最大的高度从A[0,1,...a],和右侧最大的高度从A[b, b+1, ...n-1],如果(leftmax < rightmax),那么至少leftmax - A[a]的水量可以被存进总量,而不用考虑【a,b】之间的情况,因为我们知道在右侧有一个更高的屏障(rightmax > leftmax)。同时,我们也知道,只能在a处只能存储最多leftmax - A[a]的水量,因为leftmax是左边最大的高度。所以,我们得到这样的结论,在坐标a处,我们恰能存储的水量就是leftmax - A[a]. 我们可以用同样的逻辑应用到当leftmax > rightmax。每一次循环,我们都对应的移动a或者b. 最后两者相遇时,循环结束。优化的算法,我们只需要一次扫描即可。
复杂度:O(N), 空间复杂度O(1)
AC Code:
class Solution {public: int trap(int A[], int n) { int sum = 0; int a = 0; int b = n - 1; int leftmax = 0; int rightmax = 0; while(a <= b) { leftmax = max(leftmax, A[a]); rightmax = max(rightmax, A[b]); if(leftmax < rightmax) { sum += leftmax - A[a]; a++; } else { sum += rightmax - A[b]; b--; } } return sum; }};
优化的方法,代码更加简洁,不过理解起来稍微有点难,需要对问题理解很清晰,不仅使用了动态规划,同时还利用了些贪心的思想,这个算法每个元素只被访问一次。这种两边往中间夹逼的方法也比较常用,它的核心思路就是向中间夹逼时,能确定接下来移动一侧窗口不可能使结果变得更好(不可能获得更大储水量),所以每次都能确定移动一侧指针,直到相遇为止。用到一些贪心的方法,如Two Sum, Container With Most Water.
- [C++]LeetCode: 131 Trapping Rain Water (双边扫描)
- LeetCode: Trapping Rain Water
- LeetCode : Trapping Rain Water
- [LeetCode] Trapping Rain Water
- [Leetcode] Trapping Rain Water
- [Leetcode] Trapping Rain Water
- [LeetCode]Trapping Rain Water
- LeetCode-Trapping Rain Water
- [leetcode] Trapping Rain Water
- [LeetCode] Trapping rain water
- Leetcode: Trapping Rain Water
- Leetcode:Trapping Rain Water
- [LeetCode] Trapping Rain Water
- <Leetcode>Trapping Rain Water
- Leetcode Trapping Rain Water
- leetcode Trapping Rain Water
- leetcode Trapping Rain Water
- LeetCode Trapping Rain Water
- JAVA 基本数据类型长度
- 为数据库生成表的改动日志
- spring mvc使用ehcache
- 小波变换和motion信号处理(一)
- (hdu step 2.3.7)下沙的沙子有几粒?(简单DP:求有m个H,n和D,且任意索引上H的个数都要比D的个数多的方案数)
- [C++]LeetCode: 131 Trapping Rain Water (双边扫描)
- aeroo报表使用指南
- 设置状态栏
- 语音分享应用源码项目
- Android Handler机制
- 三层数据库四大法宝之“删”
- sqlite入门基础(一):sqlite3_open,sqlite3_exec,slite3_close
- js call
- 查看LOV中查询语句