您的位置:首页 > 移动开发

leetcode: Trapping Rain Water

2013-11-07 15:09 267 查看
http://oj.leetcode.com/problems/trapping-rain-water/

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.



The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!


思路

暴力方法肯定是能解决问题的,但是复杂度只能呵呵了。园子里转过一条新闻“面试题分析:我的Twitter技术面试失败了”,里面T社面试就是这题。我不能保证这个解法效率最优,但是复杂度可以通过OJ。基本原理就是找到其中一个个小的容器区间。需要两个堆栈和一个合并区间函数配合。第一个堆栈s1的类型为stack<pair<int, int> >,用来保存容器区间;第二个堆栈s2的类型为stack<int>,用来保存边界的位置。思路如下:

如果堆栈s2为空,把当前位置压入堆栈。

如果堆栈s2不为空:
如果栈顶所在位置的值大于当前位置的值,把当前位置压入堆栈。(A[i] < A[s2.top()])

如果前一条不满足,那么当前位置的值一定大于等于栈顶所在位置的值。(A[i] >= A[s2.top()])
如果堆栈s2不为空,并更新左边界位置为栈顶元素,如果左边界上的值大于当前位置的值,停止循环,不然弹出栈顶元素并继续比较。

将当前位置压入堆栈。

把当前元素所在位置压入堆栈。同时左边界和当前元素的位置正好构成一个容器区间,根据木板原理,容积由较小的值决定。如果s1不为空,栈顶元素可以和当前元素合并,弹出栈顶元素与当前区间合并,再继续循环检查栈顶元素,如果堆栈为空或者栈顶元素不能和当前区间合并,将当前元素压入堆栈。

遍历s1并计算容积。

class Solution {
public:
bool isInRange(pair<int, int> &left, pair<int, int> &right) {
return (left.first >= right.first) && (left.second <= right.second);
}

int getVolume(int A[], pair<int, int> range) {
int left = range.first, right = range.second;
int volume = min(A[left], A[right]) * (right - left - 1);

for (int i = left + 1; i < right; ++i) {
volume -= A[i];
}

return volume;
}

int trap(int A[], int n) {
stack<pair<int, int> > ranges;
stack<int> bars;

for (int i = 0; i < n; ++i) {
if (bars.empty()) {
bars.push(i);
}
else {
if (A[i] < A[bars.top()]) {
bars.push(i);
}
else {
int left;
pair<int, int> range;

while (!bars.empty()) {
left = bars.top();
if (A[left] > A[i]) {
break;
}

bars.pop();
}

bars.push(i);
range.first = left;
range.second = i;

while (!ranges.empty()) {
if (isInRange(ranges.top(), range)) {
ranges.pop();
}
else {
break;
}
}

ranges.push(range);
}
}
}

int volume = 0;

while (!ranges.empty()) {
volume += getVolume(A, ranges.top());
ranges.pop();
}

return volume;
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: