Leetcode:接雨水(动态规划、单调栈)

https://leetcode-cn.com/problems/trapping-rain-water/

 

1.暴力法

从左向右遍历,依次找到每个点左边最高的墙和右边最高的墙,然后比较出最小的墙,再减去当前点的高度就可以得出水在这个点的积水量。

class Solution {
    public int trap(int[] height) {
        int ans = 0;
        for (int i = 1; i < height.length - 1; i++) {
            int max_left=0;//左边的最大高度
            int max_right=0;//右边的最大高度
            for (int j = i; j >=0; j--) {
                max_left = Math.max(max_left,height[j]);
            }
            for (int j = i; j < height.length; j++) {
                max_right = Math.max(max_right,height[j]);
            }
            ans+=Math.min(max_left,max_right) - height[i];
        }
        return ans;
    }
}

时间复制度O(n^2)

2.动态规划

我们注意到,解法1中。对于每个点,我们求它左边最高的墙和右边最高的墙,都是重新遍历一遍所有高度,这里我们可以优化一下。

首先用两个数组,max_left [i] 代表第 i 个点左边最高的墙的高度,max_right[i] 代表第 i 个点右边最高的墙的高度。

状态转移方程:

max_left[i] = Math.max(height[i-1],max_left[i-1]);

max_right[i] = Math.max(height[i+1],max_right[i+1]);

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

时间复制度:O(n)

3.单调栈

我们用栈保存每堵墙的下标。当遍历墙的高度的时候,如果当前高度小于栈顶的墙高度,说明这里会有积水,我们将墙的高度的下标入栈。如果当前高度大于栈顶的墙的高度,说明之前的积水到这里停下,我们可以计算下有多少积水了。计算完,就把当前的墙继续入栈,作为新的积水的墙。

class Solution {
    public int trap(int[] height) {
        Stack<Integer> stack = new Stack<>();
        int i = 0,ans = 0;
        while (i < height.length){
            while (!stack.empty() && height[stack.peek()] < height[i]){
                int x = stack.pop();//积水底部高度
                if(stack.empty()) break;;
                int d = i - stack.peek() - 1;//积水的宽度
                int h = Math.min(height[i],height[stack.peek()]) - height[x];//积水的高度
                ans+=d*h;
            }
            stack.push(i++);
        }
        return ans;
    }
}

时间复制度O(n)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值