42. Trapping Rain Water (Array,stack; DP)
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!
思路:动态规划。第一次存储从开始到i最高的位置,求最高位置a之前的存水量=a与a之前最高位置b之间的水量+b与b之前最高位置c之间的水量...
第二次存储从末尾到i最高的位置,求最高位置a之后的存水量=a与a之前最高位置m之间的水量+m与m之前最高位置n之间的水量...
class Solution { public: int trap(vector<int>& height) { int size = height.size(); if(size==0) return 0; vector<int> dp(size,0); //save the highest position until now int ret = 0; int left,right; //first traverse from left to right for(int i = 1; i < size; i++){ //state transfer if(height[i] > height[dp[i-1]]) dp[i]=i; else dp[i] = dp[i-1]; } //calculate the water to the left of the highest position left = dp[size-1]; while(left>0){ right=left; left=dp[right-1]; for(int i = left+1; i < right; i++){ ret += (height[left]-height[i]); } } //second traverse from right to highest pos int highestPos=dp[size-1]; dp[size-1]=size-1; for(int i = size-2; i >= highestPos; i--){ //state transfer if(height[i] > height[dp[i+1]]) dp[i]=i; else dp[i] = dp[i+1]; } //calculate the water to the right of the highest position right=highestPos; while(right<size-1){ left=right; right=dp[left+1]; for(int i = left+1; i < right; i++){ ret += (height[right]-height[i]); } } return ret; } };
改进:用stack代替vector作为状态存储。stack的栈顶是到目前为止最大元素的下标,因为最高位置是关键,找到最高位置,可以往左,往右计算水位。
stack的实现类似用两个stack实现能够返回最大元素的stack。
class Solution { public: int trap(vector<int>& height) { int size = height.size(); if(size==0) return 0; stack<int> s; s.push(0); int i, ret = 0, highestPos; //First traverse from left to right for(int i = 0; i < size; i++){ if(height[i]<=height[s.top()]) continue; s.push(i); } i=s.top(); highestPos = i; while(1){ if(i==s.top()){ s.pop(); if(s.empty()) break; } else{ ret+=(height[s.top()]-height[i]); } i--; } //then traverse from right to left s.push(size-1); for(int i = size-2; i >= highestPos; i--){ if(height[i]<=height[s.top()]) continue; s.push(i); } i=highestPos; while(1){ if(i==s.top()){ s.pop(); if(s.empty()) break; } else{ ret+=(height[s.top()]-height[i]); } i++; } return ret; } };