LeetCode Trapping Rain Water
class Solution { public: int trap(int A[], int n) { if (n < 1) return 0; vector<int> peaks; vector<int> peaks_tmp; int last_idx = 0; bool increasing = true; for (int i=1; i<n; i++) { if (A[i] < A[last_idx]) { if (increasing) { peaks.push_back(last_idx); } increasing = false; } else { increasing = true; } last_idx = i; } if (increasing) peaks.push_back(n - 1); if (peaks.size() < 2) return 0; bool updated = true; while (updated) { updated = false; peaks_tmp.clear(); peaks_tmp.push_back(peaks[0]); peaks_tmp.push_back(peaks[1]); for (int i=2; i<peaks.size(); i++) { int tlen = peaks_tmp.size(); int ai = peaks_tmp[tlen - 2]; int bi = peaks_tmp[tlen - 1]; int ci = peaks[i]; if (A[ai] >= A[bi] && A[ci] >= A[bi]) { peaks_tmp[tlen - 1] = ci; updated = true; } else { peaks_tmp.push_back(ci); } } swap(peaks, peaks_tmp); } int rain = 0; for (int i=1; i<peaks.size(); i++) { int left = peaks[i - 1]; int right= peaks[i]; int h = min(A[left], A[right]); int blocks = 0; for (int i=left + 1; i<right; i++) blocks += A[i] > h ? h : A[i]; rain += h * (right - left - 1) - blocks; } return rain; } };
先求出各个block的峰值,然后雨水肯定落在峰值block之间,对这些峰值block为界限的区间进行合并(对于序列A{4,1,3,1,5},第一个区间为A(0,2),第二个区间为A(2,4),由于A[4] > A[2] 且 A[0] > A[2]所以可以合并为区间A(0, 4)),直到不能继续合并,最终计算这些block区间所能积累的水量。
再稍稍改进一下,合并过程在求峰值时同时进行,额外数组减少到一个
class Solution { public: int trap(int A[], int n) { if (n < 1) return 0; vector<int> peaks; int last_idx = 0; bool increasing = true; for (int i=1; i<n; i++) { if (A[i] < A[last_idx]) { if (increasing) { peaks.push_back(last_idx); compact(A, peaks); } increasing = false; } else { increasing = true; } last_idx = i; } if (increasing) peaks.push_back(n - 1); compact(A, peaks); if (peaks.size() < 2) return 0; int rain = 0; for (int i=1; i<peaks.size(); i++) { int left = peaks[i - 1]; int right= peaks[i]; int h = min(A[left], A[right]); int blocks = 0; for (int i=left + 1; i<right; i++) blocks += A[i] > h ? h : A[i]; rain += h * (right - left - 1) - blocks; } return rain; } void compact(int A[], vector<int> &peaks) { int len = peaks.size(); if (len < 3) return; bool updated = true; while (updated && (len = peaks.size()) >= 3) { updated = false; int ai = peaks[len - 3]; int bi = peaks[len - 2]; int ci = peaks[len - 1]; if (A[ai] >= A[bi] && A[ci] >= A[bi] ) { peaks[len - 2] = ci; peaks.pop_back(); updated = true; } } } };
另外一种简洁方法参见:http://www.cnblogs.com/zhuli19901106/p/3542216.html,如下
class Solution { public: int trap(int A[], int n) { if (n < 2) return 0; vector<int> lmax(n, 0); vector<int> rmax(n, 0); int m = A[n-1]; for (int i=n-2; i >= 0; i--) { if (A[i] > m) m = A[i]; rmax[i] = m; } m = A[0]; for (int i=1; i<n; i++) { if (A[i] > m) m = A[i]; lmax[i] = m; } int rain = 0; for (int i=0; i<n; i++) { int h = min(lmax[i], rmax[i]); int v = h - A[i]; rain += v < 0 ? 0 : v; } return rain; } };
第二轮:
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!
LH数组可以不用存储直接在最后一个循环过程中计算。
1 class Solution { 2 public: 3 int trap(vector<int>& height) { 4 int len = height.size(); 5 if (len == 0) { 6 return 0; 7 } 8 vector<int> LH(len, 0); 9 LH[0] = height[0]; 10 for (int i=1; i<len; i++) { 11 LH[i] = max(LH[i-1], height[i]); 12 } 13 14 vector<int> RH(len, 0); 15 RH[len-1] = height[len-1]; 16 for (int i=len-2; i>=0; i--) { 17 RH[i] = max(RH[i+1], height[i]); 18 } 19 20 int water = 0; 21 for (int i=0; i<len; i++) { 22 int ah = min(LH[i], RH[i]); 23 if (ah <= height[i]) { 24 continue; 25 } 26 water += ah - height[i]; 27 } 28 return water; 29 } 30 };
还有更高效的做法,真是智商碾压啊,短短几行,还不用额外空间,艹
class Solution { public: int trap(vector<int>& height) { int len = height.size(); int p = 0, q = len - 1; int maxh = 0; int sum = 0; while (p < q) { if (height[p] < height[q]) { maxh = max(height[p], maxh); sum += maxh - height[p]; p++; } else { maxh = max(height[q], maxh); sum += maxh - height[q]; q--; } } return sum; } };
又从discuss中找到一种方法,似乎这种比较通用一些可以解决一些类似的问题:
class Solution { public: int trap(vector<int>& height) { int len = height.size(); stack<int> pos; int sum = 0; for (int i = 0; i < len; i++) { while (!pos.empty() && height[i] > height[pos.top()]) { int base = height[pos.top()]; pos.pop(); if (!pos.empty()) { int w = i - pos.top() - 1; int h = min(height[i], height[pos.top()]) - base; sum += w * h; } } pos.push(i); } return sum; } };
不过相比前一种使用了辅助空间。