**leetcode 42. 接雨水

【题目】42. 接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
在这里插入图片描述
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。

示例:

输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6

【解题思路1】按列求

  • 查找左边最高的墙
  • 查找右边最高的墙
  • 这一列的雨水就是两边较矮的最高的墙减去自己的高度
class Solution {
    public int trap(int[] height) {
        int sum = 0;
        //两端肯定不会有雨水
        for(int i=1; i<height.length-1; i++){
            //查找左边最高的墙,需要查找到最左端
            int max_left = 0;
            for(int j=i-1; j>=0; j--){
                if(height[j] > max_left){
                    max_left = height[j];
                }
            }
            //查找右边最高的墙,需要查找到最右端
            int max_right = 0;
            for(int j=i+1; j<height.length; j++){
                if(height[j] > max_right){
                    max_right = height[j];
                }
            }

            //这一列的雨水就是两边较矮的最高的墙减去自己的高度
            int min_max = Math.min(max_left, max_right);
            if(min_max > height[i]){
                sum += (min_max - height[i]);
            }
        }
        return sum;
    }
}

【解题思路2】动态规划

用数组记录左右两边最高的墙,减少遍历次数
数组max_left [i] 代表第 i 列左边最高的墙的高度,数组max_right[i] 代表第 i 列右边最高的墙的高度,都不包括自身。

  • max_left [i] = Max(max_left [i-1],height[i-1])
  • max_right[i] = Max(max_right[i+1],height[i+1])
class Solution {
    public int trap(int[] height) {
        int sum = 0;
        int[] max_left = new int[height.length];
        int[] max_right = new int[height.length];
        
        for (int i = 1; i < height.length - 1; i++) {
            max_left[i] = Math.max(max_left[i - 1], height[i - 1]);
        }
        for (int i = height.length - 2; i >= 0; i--) {
            max_right[i] = Math.max(max_right[i + 1], height[i + 1]);
        }
        for (int i = 1; i < height.length - 1; i++) {
            int min = Math.min(max_left[i], max_right[i]);
            if (min > height[i]) {
                sum = sum + (min - height[i]);
            }
        }
        return sum;
    }
}

【解题思路3】双指针

官方题解有动图
虽然只需要遍历一次,但是不如上面两个数组存储max值直观

class Solution {
    public int trap(int[] height) {
        int sum = 0;
        int max_left = 0;
        int[] max_right = new int[height.length];
        for (int i = height.length - 2; i >= 0; i--) {
            max_right[i] = Math.max(max_right[i + 1], height[i + 1]);
        }
        for (int i = 1; i < height.length - 1; i++) {
            max_left = Math.max(max_left, height[i - 1]);
            int min = Math.min(max_left, max_right[i]);
            if (min > height[i]) {
                sum = sum + (min - height[i]);
            }
        }
        return sum;
    }
}

【解题思路4】

class Solution {
    public int trap(int[] height) {
        int sum = 0;
        Stack<Integer> stack = new Stack<>();
        int cur = 0;
        while(cur < height.length){
            //cur比栈顶元素高时
            while(!stack.empty() && height[cur] > height[stack.peek()]){
                int h = height[stack.peek()]; //栈顶元素
                stack.pop(); //出栈
                if(stack.empty()){
                    break;
                }
                int distance = cur - stack.peek() - 1; //两堵墙之间的距离
                int min = Math.min(height[stack.peek()], height[cur]);
                sum = sum + distance * (min - h);
            }
            stack.push(cur);
            cur++;
        }
        return sum;
    }
}
发布了134 篇原创文章 · 获赞 132 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/XunCiy/article/details/105309539