题目分析
1. 这题本身问题并不是特别复杂,从左边扫一遍找到所有的左边最大值,再从右边扫一遍找到右边的最大值,再扫一遍算出每个单位的容积就可以了。
2. 但是比较有意思的是到底需要扫几遍才能够得到正确的解,从上面可以看出最朴素的算法是扫3遍。但是显然第三遍和第二遍是可以在一起完成的,因为第一遍已经得到MaxL,第二遍的时候可以同时得到MaxR和当前点的高度H,只要用Min{MaxL, MaxR} - H就可以求解出某个位置的容积了。
3.但是能不能在一遍扫描以内完成这个操作呢,就有一点麻烦,因为可以看出上面求MaxL和MaxR是要从两个不同的方向扫描得到的。我在网上看到的一个比较巧妙的思路就是用栈来描述这个过程,当序列是递减的时候不断地压栈,当序列递增的时候把栈中的元素弹出来和当前元素比较,求出对应的面积。这个思路细想还是很自然的,有点类似于下山的时候每隔一个单位放下一个锚点,拉出一条绳子,当上山的时候走到相同高度的时候测量绳子的长度,然后再把每段绳子长度叠加就得到了最终的值。
题目代码
int trap(int A[], int n) {
if(n<3) return 0;
stack<int> s;
s.push(0);
int res = 0;
for(int i=1; i<n; i++) {
int j = s.top();
if(A[i]>A[j]) {
int bottom = A[j];
s.pop();
while(!s.empty()) {
j = s.top();
int temp = std::min(A[i],A[j]);
res += (temp-bottom)*(i-j-1);
bottom = temp;
if(A[j]>=A[i])
break;
else
s.pop();
}
if(A[i]==A[j])
s.pop();
}
else if(A[i]==A[j]) //A[i]==A[j]
s.pop();
s.push(i);
}
return res;
}