看到这道题的第一想法是使用一个水平线变量level,每次将level提高1直到max{height[i]}结束循环,代码如下:
int max = -1, left = -1, capa = 0;
for(int i=0; i<height.size(); i++)
max = max<height[i]? height[i]:max;
//每次外循环结束得到高度在level以下所存储的水量
for(int level=1,j; level<=max; level++){
j = 0;
while(j<height.size()&&height[j]<level)//找到第一个大于等于level高度的点,作为水槽左端
j++;
while(height[j]>=level){
left = j;
while(j<height.size()&&height[j]<level)//找到水槽右端
j++;
if(j==height.size())//到达数组末尾则结束循环
break;
capa += j-left-1;//增加水槽装的水的容量
}
}
这个思路是:每次先找到高度大于等于level的一边,然后求高度低于level的部分也就是求高度为1的水槽的容量。
然而,很明显,这里时间复杂度为O(n*max(height)),时间性能很差。
不难发现,随着level的增大,高度大于level的点变得很少,也就是说,时间被浪费在了遍历那些低于level 的元素上,因此思路便转向如何避免重复对这些无效元素的遍历。实际上,若某个点高度为height[i],那么对任意k>i,height[i]和height[k]都可以形成一个水槽。关键在于若height[i]<=height[k],则height[i]就无法与height[j](j>k)形成水槽,因此有了以下算法。
int trap(vector<int>& height) {
int capa = 0, size = height.size(), ll = 0;
stack<int> s;
for(int i=0; i<size; i++){
ll = 0;
while(s.size()>0&&height[s.top()]<=height[i]){
capa += (height[s.top()]-ll)*(i-s.top()-1);
ll = height[s.top()];
s.pop();
}
if(s.size()>0){
capa += (height[i]-ll)*(i-s.top()-1);
}
s.push(i);
}
return capa;
}