这题一模一样的在字节面试里看到过
leetcode面试提17.21.直方图的雨量
解法一:
- 找到最高的长方形
- 在每个子图中找到第二高的长方形
- 计算最高长方形和第二高的长方形中的积水面积
- 以该图的边界进行递归
class Solution {
public:
int trap(vector<int>& height) {
int start = 0;
int end = height.size()-1;
int max = findIndexOfMax(height,start,end);
int leftVolume = subgraphVolume(height,start,max,true);
int rightVolume = subgraphVolume(height,max,end,false);
return leftVolume+rightVolume;
}
//计算直方图的子面积
int subgraphVolume(vector<int>& height,int start,int end,bool isLeft){
if(start>=end)
return 0;
int sum = 0;
if(isLeft){
int max = findIndexOfMax(height,start,end-1);
sum+=borderedVolume(height,max,end);
sum+=subgraphVolume(height,start,max,isLeft);
}else{
int max = findIndexOfMax(height,start+1,end);
sum+=borderedVolume(height,start,max);
sum+=subgraphVolume(height,max,end,isLeft);
}
return sum;
}
//计算start与end之间的最高长方形
int findIndexOfMax(vector<int>& height,int start,int end){
int indexOfMax = start;
for(int i = start+1;i<=end;i++){
if(height[i]>height[indexOfMax])
indexOfMax = i;
}
return indexOfMax;
}
//计算start与end之间的面积
int borderedVolume(vector<int>& height,int start,int end){
if(start>=end)
return 0;
int min = height[start]>height[end]?height[end]:height[start];//找到最小的
int sum = 0;
for(int i=start+1;i<end;i++){
sum+=min-height[i];//计算面积
}
return sum;
}
};
解法二:从每个点的角度来优化算法
优化点:解法一会不断调用findIndexOfMax寻找最高长方形,可以事先扫描一遍得到所有的信息,花费O(N)时间
对于vector中每个点,水有多高取决于这个点左侧和右侧墙壁的最大高度。
第一个for循环找每个点的左侧最大高度,第二个for循环找每个点右侧的最大高度,循环中跳过最左侧(i=0)和最右侧点(i=vector.size()-1)的原因是这两个点由于没有左侧墙壁或右侧墙壁所以最大墙壁高度肯定是0,故在初始化vector的时候已经将其默认设置成0了。在得到所有点的左右墙壁最大高度后,木桶原理取左右墙壁较低的那个高度减去当前位置墙壁作为地面的高度就得到了这个位置上水的高度。然后将所有点的水高度相加即为解。
class Solution {
public:
int trap(vector<int>& height) {
int n = height.size();
// left[i]表示i左边的最大值,right[i]表示i右边的最大值
vector<int> left(n),right(n);
for(int i=1;i<n;i++)
left[i] = max(left[i-1],height[i-1]);
for(int i=n-2;i>=0;i--)
right[i] = max(right[i+1],height[i+1]);
int water = 0;
for(int i=0;i<n;i++){
int level = min(left[i],right[i]);
water+=max(0,level-height[i]);//记得要和0比较,否则会出现负值
}
return water;
}
};