有一周没更新博客了,过去的一周打击太大,哎!不说了,还是继续leetcode吧!
原题如下:
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!
这道题乍一看似曾相识,因为之前有一道求面积最大的题目,解那道题是利用两个指针分别从头和尾开始扫描。但此题用那种解法显然不行,因为当前位置的储水量不仅跟前后位置相关,而且跟前后的历史数据相关,所以需要利用数组分别保存每个节点前后的最大值,具体思路如下:
每个节点的储水量是由其前边的最大值和后边的最大值中的最小值决定的,具体的计算公式是:sum = min(maxleft,maxright)- A[i],在C++编程时,可以创建两个vector分别保存当前节点的左边的最大值和右边的最大值,这需要两次扫描数组,然后再次遍历数组求解即可,算法的时间复杂度是O(n),空间复杂度O(n)。
class Solution {
public:
int trap(int A[], int n) {
if( n == 0 || n == 1 || n == 2)
return 0;
vector<int>mv1(n);
vector<int>mv2(n);
mv1[0] = A[0];
for(int i = 1; i < n; i++){
mv1[i] = mv1[i-1] > A[i] ? mv1[i-1] : A[i];
}
mv2[n - 1] = A[n - 1];
for(int i = n - 2; i > 0; i--)
mv2[i] = mv2[i + 1] > A[i] ? mv2[i + 1]: A[i];
mv2[0] = A[0];
int sum = 0;
for(int i = 1; i < n - 1; i++){
int temp = mv1[i] < mv2[i] ? mv1[i] : mv2[i];
temp -= A[i];
if(temp > 0)
sum += temp;
}
return sum;
}
};
注:在使用vector时,如果在声明时设定了其容量大小,则可以当做数组使用,且此时每pushback()一次其容量加1。
补:由于在求出节点右边的最大值后,当前节点的储水量即可算出来,所以可以在求右边节点最大值的过程中求解储水量,这样只需保存右边节点的最大值而不必利用数组把每个节点的最大值都存储起来,而且这样减少了一次数组遍历。
int trap(int A[], int n) {
if(n == 0 || n == 1 || n == 2)
return 0;
int *maxLeft = new int[n];
int maxRight = 0;
int sum = 0;
int minMax = 0;
int diff = 0;
maxLeft[0] = A[0];
for(int i = 1; i < n; i++){
maxLeft[i] = A[i] > maxLeft[i - 1]? A[i]: maxLeft[i - 1]; //i左边的最大值(包含i)
}
maxRight = A[n - 1];
for(int i = n - 2; i > 0; i--){
maxRight = A[i] > maxRight? A[i] : maxRight; //i右边的最大值(包含i)
minMax = maxRight < maxLeft[i]?maxRight :maxLeft[i];
diff = minMax - A[i];
if(diff > 0)
sum +=diff;
}
return sum;
}