• 【LeetCode】42.接雨水


    题目链接

    42. 接雨水

    题目描述

    解题思路

    暴力法(按列求取雨水值)

    因为首尾元素不可能存在雨水,所以可以不用考虑首尾元素。

    对于剩余的每个元素,分别计算从该元素开始,从左和从右开始开始的最大值,然后当前元素对应的能够接的雨水值 = Math.min(maxLeft,maxRight) - height[i];

    时间复杂度:O(n2)

    空间复杂度:O(1)

    动态规划

    在暴力法中,我们每次都要计算当前坐标对应的左边最大值maxLeft以及右边最大值maxRight,所以直接导致时间复杂度为O(n2),然而这些值都是固定的,所以我们可以提前利用两个数组maxleft[]以及maxRight[]记录每个下标对应的左边最大值和右边最大值。

    时间复杂度:O(n)

    空间复杂度:O(n)

    单调栈

    单调递减栈,栈中存放的是索引值,因为通过索引值也可以得到height数组中的元素值。

    如果当前索引对应的height数组值 <= 前一个索引对应的height数组值,那么接不雨水。

    如果当前索引对应的height数组值 > 前一个索引对应的height数组值,那么才有可能接到雨水(注意是有可能,而不是一定,只有同时满足单调栈不为空的时候才能接到雨水)

    参考下图就一目了然,利用单调栈也可以理解为是按行计算雨水值

    如果当前下标对应的height数组值小于栈顶元素则入栈。

    如果当前下标对应的height数组值大于栈顶元素且当前stack不为空,则说明此时这种情况存在雨水值,雨水值的计算方式如下:

    • 首先记录value = 弹栈元素对应的height数组值
    • 其次记录Math.min(新的栈顶元素对应的height数组值,以及当前索引对应的height数组值),然后减去value值,则为水坑对应的高度。
    • 水坑的宽度 = 当前索引 - 新的栈顶元素。

    参考资料

    AC代码

    暴力法

    class Solution {
        //按照每列的雨水数目计算结果
        public int trap(int[] height) {
            int ans = 0;
            //因为开头结尾不会有雨水,所以可以不用考虑
            for(int i = 1; i < height.length - 1; i++){
                int maxLeft = height[i];
                int maxRight = height[i];
                for(int j = i - 1; j >= 0; j--){
                    if(height[j] > maxLeft){
                        maxLeft = height[j];
                    }
                }
                for(int j = i + 1; j < height.length; j++){
                    if(height[j] > maxRight){
                        maxRight = height[j];
                    }
                }
                ans += Math.min(maxLeft,maxRight) - height[i];
            }
            return ans;
        }
    }
    

    动态规划

    class Solution {
        public int trap(int[] height) {
            if(height.length == 0) return 0;
            int maxLeft[] = new int[height.length];
            int maxRight[] = new int[height.length];
            int ans = 0;
            maxLeft[0] = 0;
            for(int i = 1; i < height.length; i++){
                maxLeft[i] = Math.max(height[i - 1],maxLeft[i-1]);
            }
            maxRight[height.length-1] = 0;
            for(int i = height.length - 2; i >= 0; i--){
                maxRight[i] = Math.max(height[i+1],maxRight[i+1]);
            }
            for(int i = 1; i < height.length; i++){
                int h = Math.min(maxLeft[i],maxRight[i]);
                if(h > height[i]){
                    ans += h - height[i];
                }
            }
            return ans;
        }
    }
    
    //改进版动态规划
    class Solution {
        public int trap(int[] height) {
            if(height.length == 0) return 0;
            int maxRight[] = new int[height.length];
            int ans = 0;
            int maxLeft = 0;
            maxRight[height.length-1] = 0;
            for(int i = height.length - 2; i >= 0; i--){
                maxRight[i] = Math.max(height[i+1], maxRight[i+1]);
            }
            for(int i = 1; i < height.length; i++){
                maxLeft = Math.max(maxLeft,height[i - 1]);
                int h = Math.min(maxLeft,maxRight[i]);
                if(h > height[i]){
                    ans += h - height[i];
                }
            }
            return ans;
        }
    }
    
    //改进版,双指针法
    public int trap(int[] height) {
        int sum = 0;
        int max_left = 0;
        int max_right = 0;
        int left = 1;
        int right = height.length - 2; // 加右指针进去
        for (int i = 1; i < height.length - 1; i++) {
            //从左到右更
            if (height[left - 1] < height[right + 1]) {
                max_left = Math.max(max_left, height[left - 1]);
                int min = max_left;
                if (min > height[left]) {
                    sum = sum + (min - height[left]);
                }
                left++;
            //从右到左更
            } else {
                max_right = Math.max(max_right, height[right + 1]);
                int min = max_right;
                if (min > height[right]) {
                    sum = sum + (min - height[right]);
                }
                right--;
            }
        }
        return sum;
    }
    
    作者:windliang
    链接:https://leetcode-cn.com/problems/trapping-rain-water/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-8/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    

    单调栈

    class Solution {
        public int trap(int[] height) {
            Stack<Integer> st = new Stack<>();
            int ans = 0;
            for(int i = 0; i < height.length; i++){
                while(!st.isEmpty() && height[i] > height[st.peek()]){
                    int index = st.pop();
                    int value = height[index];
                    if(st.isEmpty() == false) ans += (Math.min(height[st.peek()],height[i]) - value) * (i-st.peek()-1);
                }
                st.push(i);
            }
            return ans;
        }
    }
    
  • 相关阅读:
    36-图像有用区(dfs, bfs)
    35-迷宫寻宝(一)-NYOJ82
    34- 24 Point game
    32-回文字符串(dp)
    71-n皇后
    70-合并数字
    2017.11.18 C语言的算法分析题目
    2017.11.17 C++系列---用malloc动态给c++二维数组的申请与释放操作
    2017.11.16 JavaWeb-------第八章 EL、JSTL、Ajax技术
    2017.11.15 JavaWeb的学生体质管理系统
  • 原文地址:https://www.cnblogs.com/XDU-Lakers/p/14194856.html
Copyright © 2020-2023  润新知