<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">题目来源:https://leetcode.com/problems/trapping-rain-water/</span>
题目描述:
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
.
解题思路:题目意思是说给定一个非负数的一维数组,数组中元素的值表示阶梯的高度,如上图中的黑色部分,阶梯的宽度都是1,问最多可以存储多少雨水?
容易想到的是高的阶梯之间可以存储较多的雨水,所以解题的第一步就是找出峰值阶梯,即给定的数组中的峰值,同时满足height[i]>=height[i-1]和height[i]>=height[i+1]的即为峰值,头尾两个阶梯只要满足大于相邻的一个阶梯即可。找出的峰值存于数组posI中。(如下面程序所示)
第二步是找出posI中的两个最大值,分别存于变量maxPos1和maxPos2中,从而将整个数组分为三个部分,两个最大值中间的部分,左边的部分和右边的部分。
第三步是找出用于计算雨水量的关键阶梯,如下面程序所示。
程序代码:
int trap(vector<int>& height){
vector<int> posI;
vector<int> posIICenter;
vector<int> posIILeft;
vector<int> posIIRight;
int waterSum = 0, sum = 0, lowWidth = 0,waterSumLeft=0,waterSumRight=0,waterSumCenter=0;
int count = 0, maxPos1 = 0,maxPos2=0,maxLeftTemp=0,maxRightTemp=0,lastLeft=0,lastRight=0;
bool leftFlag = false, rightFlag = false;
//construct posI
if (height.size()<2) return 0;
if (height[0]>height[1]) {
posI.push_back(0);
}
for (int i = 1; i < height.size() - 1; i++){
if (height[i] >= height[i - 1] && height[i] >= height[i + 1]){
posI.push_back(i);
}
}
if (height[height.size() - 1]>height[height.size() - 2]) {
posI.push_back(height.size() - 1);
}
//construct posII=posIILegt+posIICenter+posIIRight
if (posI.size() < 2) return 0;
for (int i = 1; i < posI.size(); i++){// find max peak
if (height[posI[i]]>=height[posI[maxPos1]]){
maxPos1 = i;
}
}
if (maxPos1==0){
maxPos2 = 1;
for (int i = 2; i <posI.size();i++){
if (height[posI[i]]>=height[posI[maxPos2]]){
maxPos2 = i;
}
}
}
else{
for (int i = 1; i < posI.size(); i++){//find second max peak
if (height[posI[i]] >= height[posI[maxPos2]] && i != maxPos1){
maxPos2 = i;
}
}
}
if (maxPos1 > maxPos2){
int temp = maxPos1;
maxPos1 = maxPos2;
maxPos2 = temp;
}
posIICenter.push_back(posI[maxPos1]);
posIICenter.push_back(posI[maxPos2]);
if (maxPos1 > 0){
posIILeft.push_back(posI[maxPos1]);
for (int i = 0; i < maxPos1; i++){
if (height[posI[i]] >= height[posI[maxLeftTemp]]){
maxLeftTemp = i;
}
}
posIILeft.push_back(posI[maxLeftTemp]);
if (maxLeftTemp == 0){
leftFlag = true;
}
while (!leftFlag){
lastLeft = maxLeftTemp;
maxLeftTemp = lastLeft-1;
for (int i = lastLeft-2; i > -1; i--){
if (height[posI[i]] >= height[posI[maxLeftTemp]]){
maxLeftTemp = i;
}
}
if (maxLeftTemp == 0){
leftFlag = true;
}
posIILeft.push_back(posI[maxLeftTemp]);
}
}//maxPos1>0
if (maxPos2 < posI.size()-1){
posIIRight.push_back(posI[maxPos2]);
maxRightTemp = posI.size() - 1;
for (int i = posI.size() - 2; i>maxPos2; i--){
if (height[posI[i]] > height[posI[maxRightTemp]]){
maxRightTemp = i;
}
}
posIIRight.push_back(posI[maxRightTemp]);
if (maxRightTemp == posI.size() - 1){
rightFlag = true;
}
while (!rightFlag){
lastRight = maxRightTemp;
maxRightTemp = lastRight + 1;
for (int i = lastRight+2; i < posI.size(); i++){
if (height[posI[i]] >= height[posI[maxRightTemp]]){
maxRightTemp = i;
}
}
posIIRight.push_back(posI[maxRightTemp]);
if (maxRightTemp == posI.size() - 1){
rightFlag = true;
}
}
}//maxPos2 < posI.size()-1
//caculate rainwater
// waterSum=waterSumLeft+waterSumCenter+waterSumRight
if (height[posI[maxPos1]] >= height[posI[maxPos2]]){
for (int i = posI[maxPos1] + 1; i < posI[maxPos2]; i++){
if (height[i] < height[posI[maxPos2]]){
sum = sum + height[i];
lowWidth = lowWidth + 1;
}
}
waterSumCenter = height[posI[maxPos2]] * lowWidth - sum;
}
else{
for (int i = posI[maxPos1] + 1; i < posI[maxPos2]; i++){
if (height[i] < height[posI[maxPos1]]){
sum = sum + height[i];
lowWidth = lowWidth + 1;
}
}
waterSumCenter = height[posI[maxPos1]] * lowWidth - sum;
}
sum = 0;
lowWidth = 0;
if (posIILeft.size() > 1){
for (int i = 0; i<posIILeft.size() - 1; i++){
sum = 0;
lowWidth = 0;
for (int j = posIILeft[i+1] + 1; j<posIILeft[i]; j++){
if (height[j] < height[posIILeft[i + 1]]){
sum = sum + height[j];
lowWidth = lowWidth + 1;
}
}
waterSumLeft = waterSumLeft + height[posIILeft[i + 1]] * lowWidth - sum;
}
}
sum = 0;
lowWidth = 0;
if (posIIRight.size() > 1){
for (int i = 0; i<posIIRight.size() - 1; i++){
sum = 0;
lowWidth = 0;
for (int j = posIIRight[i] + 1; j < posIIRight[i + 1]; j++){
if (height[j] < height[posIIRight[i + 1]]){
sum = sum + height[j];
lowWidth = lowWidth + 1;
}
}
waterSumRight = waterSumRight + height[posIIRight[i+1]] * lowWidth - sum;
}
}
waterSum = waterSumLeft + waterSumCenter + waterSumRight;
return waterSum;
}