for (let i =0; i <height.length; i++) { area += (h[i] - height[i]) *1; // h为下雨之后的水位}
问题转化为求 h 数组,这里 h[i] 其实等于左右两侧柱子的最大值中的较小值,即 h[i] = Math.min(左边柱子最大值, 右边柱子最大值)
如上图那么 h 为 [0, 1, 1, 2, 2, 2 ,2, 3, 2, 2, 2, 1]
问题的关键在于求解左边柱子最大值和右边柱子最大值, 我们其实可以用两个数组来表示leftMax, rightMax, 以 leftMax 为例,leftMax[i]代表 i 的左侧柱子的最大值,因此我们维护两个数组即可。
关键点解析
建模 h[i] = Math.min(左边柱子最大值, 右边柱子最大值)(h 为下雨之后的水位)
代码
代码支持: JS, Python3, C++:
JS Code:
/* * @lc app=leetcode id=42 lang=javascript * * [42] Trapping Rain Water * *//** * @param{number[]} height * @return{number} */vartrap=function (height) {let max =0;let volume =0;constleftMax= [];constrightMax= [];for (let i =0; i <height.length; i++) { leftMax[i] = max =Math.max(height[i], max); } max =0;for (let i =height.length-1; i >=0; i--) { rightMax[i] = max =Math.max(height[i], max); }for (let i =0; i <height.length; i++) { volume = volume +Math.min(leftMax[i], rightMax[i]) - height[i]; }return volume;};
Python Code:
classSolution:deftrap(self,heights: List[int]) ->int: n =len(heights) l, r = [0] * n, [0] * n ans =0for i inrange(1, len(heights)): l[i]=max(l[i -1], heights[i -1])for i inrange(len(heights) -2, 0, -1): r[i]=max(r[i +1], heights[i +1])for i inrange(len(heights)): ans +=max(0, min(l[i], r[i]) - heights[i])return ans
C++ Code:
inttrap(vector<int>& heights){if(heights == null)return0;int ans =0;int size =heights.size(); vector<int>left_max(size),right_max(size);left_max[0] =heights[0];for (int i =1; i < size; i++) {left_max[i] =max(heights[i],left_max[i -1]); }right_max[size -1] =heights[size -1];for (int i = size -2; i >=0; i--) {right_max[i] =max(heights[i],right_max[i +1]); }for (int i =1; i < size -1; i++) { ans +=min(left_max[i],right_max[i]) -heights[i]; }return ans;}
复杂度分析
时间复杂度:$O(N)$
空间复杂度:$O(N)$
双指针
这种解法为进阶解法, 大家根据自己的情况进行掌握。
思路
上面代码比较好理解,但是需要额外的 N 的空间。从上面解法可以看出,我们实际上只关心左右两侧较小的那一个,并不需要两者都计算出来。具体来说:
classSolution:deftrap(self,heights: List[int]) ->int: n =len(heights) l_max = r_max =0 l, r =0, n -1 ans =0while l < r:if heights[l]< heights[r]:if heights[l]< l_max: ans += l_max - heights[l]else: l_max = heights[l] l +=1else:if heights[r]< r_max: ans += r_max - heights[r]else: r_max = heights[r] r -=1return ans
C++ Code:
classSolution {public:inttrap(vector<int>& heights){int left =0, right =heights.size() -1;int ans =0;int left_max =0, right_max =0;while (left < right) {if (heights[left] <heights[right]) {heights[left] >= left_max ? (left_max =heights[left]) : ans += (left_max -heights[left]);++left; }else {heights[right] >= right_max ? (right_max =heights[right]) : ans += (right_max -heights[right]);--right; } }return ans;}};
Go Code:
functrap(height []int) int {iflen(height) ==0 {return0 } l, r :=0, len(height)-1 lMax, rMax := height[l], height[r] ans :=0for l < r {if height[l] < height[r] {if height[l] < lMax { ans += lMax - height[l] } else { lMax = height[l] } l++ } else {if height[r] < rMax { ans += rMax - height[r] } else { rMax = height[r] } r-- } }return ans}