LeetCode_42_接雨水

题目描述:
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
在这里插入图片描述
示例:

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

方法 1:暴力
直观想法

直接按问题描述进行。对于数组中的每个元素,我们找出下雨后水能达到的最高位置,等于两边最大高度的较小值减去当前高度的值。

算法

初始化 ans=0
从左向右扫描数组:
初始化max_left=0 和max_right=0
从当前元素向左扫描并更新:max_left=max(max_left,height[j])
从当前元素向右扫描并更新:max_right=max(max_right,height[j])
将min(max_left,max_right)−height[i] 累加到 ans

代码:

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

方法 2:动态编程
直观想法

在暴力方法中,我们仅仅为了找到最大值每次都要向左和向右扫描一次。但是我们可以提前存储这个值。因此,可以通过动态编程解决。

这个概念可以见下图解释:

在这里插入图片描述
算法

找到数组中从下标 i 到最左端最高的条形块高度 left_max。
找到数组中从下标 i 到最右端最高的条形块高度 right_max。
扫描数组height 并更新答案:
累加 min(max_left[i],max_right[i])−height[i] 到 ans 上

  public int trap(int[] height) {
        if (height==null||height.length==0)
            return 0;
        int ans=0;
        int size=height.length;
        int[] left_max=new int[size];
        int[] right_max=new int[size];
        left_max[0]=height[0];
        for (int i=1;i<size;i++){
            left_max[i]=Math.max(height[i],left_max[i-1]);
        }
        right_max[size-1]=height[size-1];
        for (int i=size-2;i>=0;i--){
            right_max[i]=Math.max(height[i],right_max[i+1]);
        }
        for (int i=1;i<size-1;i++){
            ans+=Math.min(left_max[i],right_max[i])-height[i];
        }
        return ans;
    }

方法 3:栈的应用
直观想法

我们可以不用像方法 2 那样存储最大高度,而是用栈来跟踪可能储水的最长的条形块。使用栈就可以在一次遍历内完成计算。

我们在遍历数组时维护一个栈。如果当前的条形块小于或等于栈顶的条形块,我们将条形块的索引入栈,意思是当前的条形块被栈中的前一个条形块界定。如果我们发现一个条形块长于栈顶,我们可以确定栈顶的条形块被当前条形块和栈的前一个条形块界定,因此我们可以弹出栈顶元素并且累加答案到 ans 。

代码:

 public int trap(int[] height) {
        int ans=0,current=0;
        Stack<Integer>  stack=new Stack<>();
        while (current<height.length){
            while (!stack.empty()&&height[current]>height[stack.peek()]){
                int top= stack.pop();
                if (stack.empty())
                    break;
                int distance=current-stack.peek()-1;
                int bounded_height=Math.min(height[current],height[stack.peek()])-height[top];
                ans+=distance*bounded_height;
            }
            stack.push(current++);
        }
        return ans;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值