给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
输入输出样式输入:height = [0,1,0,2,1,0,1,3,2,1,2,1] 输出:6 解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
输入:height = [4,2,0,3,2,5] 输出:9解法一:按行求(AC时间超出)
一层一层的计算水的高度,但是递交AC会时间报错
int trap(vector解法二,暴力解法,遍历两边的最大最小值(AC超时)&height) { int left=0,right=0; int length=height.size(); int maxValue,maxIndex; int sum=0; //建立临时数组保存height对其进行去重和排序 vector tempArray=height; sort(tempArray.begin(),tempArray.end()); auto newArray=unique(tempArray.begin(),tempArray.end()); tempArray.erase(newArray,tempArray.end()); //跳过第一元素为0的情况 int i=0; while(i if(height[i]==0) { i++; } else{ left=i; break; } } //获得最大值的下标 maxIndex=max_element(height.begin()+left,height.end())-height.begin(); maxValue=height[maxIndex]; if(tempArray.size()==1) { return 0; } i=tempArray[1]; int j=1; while(i<=maxValue&&j vector countArray; for(int index=0;index if(height[index]>=i) { countArray.push_back(1); } else{ countArray.push_back(0); } } int tempValue=areaCount(countArray,tempArray[j-1],tempArray[j]); sum+=tempValue; countArray.clear(); j++; if(j>=tempArray.size()) { break; } i=tempArray[j]; } return sum; } int areaCount(vector countArray,int min,int now) { int left=0,right=0; int sum=0; //找到第一个点的坐标并赋给左边 for(int i=0;i if(countArray[i]==1) { left=i; break; } } for(int i=left+1;i if(countArray[i]==1) { right=i; sum=sum+(right-left-1)*(now-min); left=i; } } return sum; }
//使用暴力解法,对于数组中的每一个元素,找出下雨后雨水能达到的最高位置,等于两边最大高度的较小值减去当前高度的值
int trap2(vector&height)
{
int ans=0;
int length=height.size();
for(int i=1;i
int maxLeft=0,maxRight=0;
//找出元素左边的最大值
for(int j=i;j>=0;j--)
{
maxLeft=max(maxLeft,height[j]);
}
//找出元素右边的最大值
for(int j=i;j
maxRight=max(maxRight,height[j]);
}
//当前元素能存的水量。是两个最大值中较小的哪一个减去当前元素的值
ans+=min(maxLeft,maxRight)-height[i];
}
return ans;
}
解法三,动态规划,两数组保存左右最大的值
//解法三,采用的是动态规划的方法,解法与解法二的相同,其区别在于提前将各个数对应的左边最大值和右边最大值存储进来
int trap3(vector&height)
{
int length=height.size();
if(!length)
{
return 0;
}
int ans=0;
//建立数组保存左右两边的最大值
vectorleftMax(length),rightMax(length);
//初始化两数组的值
leftMax[0]=height[0];
rightMax[length-1]=height[length-1];
//寻找并更新左右两侧的最大值
for(int i=1;i
leftMax[i]=max(height[i],leftMax[i-1]);
}
for(int i=length-2;i>=0;i--)
{
rightMax[i]=max(height[i],rightMax[i+1]);
}
//找到两者中的最小值,然后减去当前的高度
for(int i=1;i
ans+=min(leftMax[i],rightMax[i])-height[i];
}
return ans;
}
解法四,使用堆栈,找出单调不递减序列
//解法四,使用单调递减栈存储可能储水的柱子,当找到一根比前面高的柱子,便可计算接到的雨水
int trap4(vector&height)
{
int ans=0;
int current=0;
stackstk;
while(current
//当栈不为空,当前高度大于栈顶元素,当出现非递增时,进行判断
//主要关注栈顶的元素
//和栈顶的第二个元素
while(!stk.empty()&&height[current]>height[stk.top()])
{
//栈顶第一个元素出栈,这个是最小的值
int top=stk.top();
stk.pop();
//当只有两个符合条件的便出栈
if(stk.empty())
{
break;
}
//计算坐标之间的距离
int distance=current-stk.top()-1;
int boundedHeight=min(height[current],height[stk.top()])-height[top];
ans+=distance*boundedHeight;
}
//先将current加入堆栈中,再递增current
stk.push(current++);
}
return ans;
}
解法五,使用双指针方法,利用左右指针二者的大小关系
//解法5,使用双指针的方法
int trap5(vector&height)
{
int left=0,right=height.size()-1;
int ans=0;
int leftMax=0,rightMax=0;
while(left
//当左边的值小于右边,则当前坐标可容纳的水量是由leftmax 决定的
if(height[left]
if(height[left]>=leftMax)
{
leftMax=height[left];
}
else{
ans+=(leftMax-height[left]);
}
left++;
}
//当右边的值小于左边,则当前坐标可容纳的水量是由righeMax决定的
else
{
if(height[right]>=rightMax)
{
rightMax=height[right];
}
else{
ans+=(rightMax-height[right]);
}
right--;
}
}
return ans;
}



