问题描述
leetcode42 接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
将数组的大小当作是木板的高度,这样一个高低不一的板子竖着放,能放多少水?
解决思路
我的思路很简单,就是按照需要找到凹形状的区域的首位索引,将所有凹形状的盛水量。加起来即可。
* 一遍循环,从头开始遍历,寻找值不小于当前元素的索引
* 如果有,则计算这一段凹形状的盛水量,i 挪到该形状的末尾处
* 如果没有,则则找出当前位置 后面元素中的所出现的最后一个最大值。为什么要最后一个出现的,其实是为了
* 节省时间,画个图来看就知道了。i 继续挪到该凹形状的末尾处
* 如果上述情况都不符合,则 i 自增。
这个简单的思路居然还超过了99的人。。果然最基础的就是最完美的。。。。。。
代码呈现
1 public class Solution { 2 public static int trap(int[] height) { 3 if (height.length==0) { return 0;} 4 int res = 0; 5 int i=0; 6 while ( i < height.length ) { 7 int findFlag = findBig(height, i); 8 int next = findSmall(height, i); 9 if (findFlag > 0) { 10 System.out.println("i:"+i); 11 System.out.println("j:"+findFlag); 12 System.out.println(); 13 res += helper(height, i, findFlag); 14 i = findFlag; 15 } else if (next > 0) { 16 res += helper(height, i, next); 17 i =next; 18 } else { i++; } 19 } 20 return res; 21 } 22 23 private static int helper(int[] nums, int left, int right) { 24 /* 25 * 计算这一凹形状的盛水量。 26 */ 27 int curSum = nums[left] < nums[right] ? nums[left] : nums[right]; 28 curSum = curSum * (right-left-1); 29 for (int i = left+1; i<right; i++) { 30 curSum -= nums[i]; 31 } 32 return curSum; 33 } 34 35 private static int findBig(int[] nums, int start) { 36 /* 37 * 在当前元素后面找到不小于当前元素的下标。有,则返回。无,则返回 -1。 38 */ 39 for (int i=start+1; i<nums.length; i++) { 40 if (nums[i] >= nums[start]) { return i; } 41 } 42 return -1; 43 } 44 45 private static int findSmall(int[] nums, int start) { 46 /* 47 * 如果当前元素比后面所有都要大,则找出当前位置 后面元素中的所出现的最后一个最大值。 48 */ 49 if (start+1<nums.length) { 50 int max=nums[start+1]; 51 int index = start+1; 52 for(int i = nums.length-1; i>start; i--) { 53 if (nums[i] > max) { 54 max = nums[i]; 55 index = i; 56 } 57 } 58 if (index == start +1) { 59 return -1; 60 } 61 62 return index; 63 } 64 65 return -1; 66 } 67 }
在看了标准答案后,发现自己的思路虽然简单,但是代码量就有点大了。答案给了三种解法:动态规划、左右指针、栈方法。
其中栈方法自己应该想出来的。可惜了,但是这几种方法虽然代码简洁,但是思考起来还是很困难。
栈方法解法如下:
1 class Solution { 2 public int trap(int[] height) { 3 if (height == null || height.length == 0) return 0; 4 Deque<Integer> stack = new ArrayDeque<>(); 5 int res = 0; 6 for (int i = 0; i < height.length; i++){ 7 while ( ! stack.isEmpty() && height[stack.peek()] < height[i]) { 8 int tmp = stack.pop(); 9 if (stack.isEmpty()) break; 10 res += (Math.min(height[i],height[stack.peek()]) - height[tmp]) * (i - stack.peek() - 1); 11 } 12 stack.push(i); 13 } 14 return res; 15 } 16 }