力扣42题,接雨水的问题,单栈和双栈法解决接雨水问题

版权声明:本文为HCG自己总结的文章,有不理解的或者错误的地方请联系[email protected] https://blog.csdn.net/qq_39455116/article/details/91412880

1. 单个存储栈

  * 其实某一格能容纳的水量one就是:
     * one= max(left)-max(right)- arr[i]
     * 如果小于等于0 ==0
     * 如果大于0才有值
     * 问题就到了找到每一个arr[i]左右两边的最大值


* 最直观想到的就是用两个栈,分别存截止到当前元素arr[i]的左右两边的最大值
* stack<Integer> leftMax 代表左边的,从0到arr[i]遍历,只有在当前值大于栈中的值时才入栈,但是
* 仔细想了一下,好像没有必要用到栈,因为不涉及弹出,最后用一个变量 maxLeft代表吧
* stack<Integer> rightMax 代表右边的 ,顺序先从左到右,我们发现如果第一个值如果最大,
* 后面的就不入栈了,所以左----》右的顺序不行
* 如果是从最右边到arr[i+1]是可以了,而且是可以弹出的,所以我们右边用栈来表示
package com.pf.org.cms.yushui;


import java.util.Stack;

public class DongTai {


 
    public static int trap(int[] height) {
        /**
         * 因为想存水至少需要3个
         */
        if (height.length <= 2) {
            return 0;
        }
        /***
         * 总存水量
         */
        int maxShui = 0;

        /***
         * 单个格子的存水量
         */
        int oneShui = 0;

        /***
         * maxLeft要存的是从第1个arr[0]到倒数第二个arr[i-1]之间的最大值
         */
        int maxLeft = 0;
        /***
         * rightStack 要存的是从第3个arr[2]到最后一个arr[len-1]之间所有的最大值
         */
        Stack<Integer> rightStack = new Stack<>();

        /**
         * 先放入最后一个
         */
        rightStack.push(height[height.length - 1]);
        /**
         * 从倒数第二个开始,到正数第三个也就是arr[2]结束
         */
        for (int i = height.length - 2; i > 1; i--) {
            if (height[i] > rightStack.peek()) {
                rightStack.push(height[i]);
            } else {
                rightStack.push(rightStack.peek());
            }
        }


        /***
         * 因为第一个格子和最后一个格子是存不了水的
         */
        for (int i = 1; i < height.length - 1; i++) {
            if (height[i - 1] > maxLeft) {
                maxLeft = height[i - 1];
            }
            oneShui = Math.min(maxLeft, rightStack.pop()) - height[i];
            if (oneShui < 0) {
                oneShui = 0;
            }
            System.out.println(i + "    " + oneShui);
            maxShui += oneShui;

        }
        return maxShui;

    }

    public static void main(String[] args) {
        int arr[] = new int[]{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1};
        System.out.println(trap(arr));
    }

}


输出结果:

1    0
2    1
3    0
4    1
5    2
6    1
7    0
8    0
9    1
10    0
6

力扣分析:

执行用时 :13 ms, 在所有Java提交中击败了40.74%的用户
内存消耗 :36.2 MB, 在所有Java提交中击败了92.01%的用户

2. 简化单存储栈,但是需要额外添加一个栈

在上面的栈存储上面,存的是1 222 333 333其实数量如果大的话,其中的2和3如果能存一个就好了
变成1 2 3但是再利用一个栈存入栈的下标,比如上述的 11 10 7

2.1 这就是典型的以空间换取时间的算法

/***
 * rightStack 要存的是从第3个arr[2]到最后一个arr[len-1]之间所有的最大值
 * 最后变为 1 2 3
 */
Stack<Integer> rightStack = new Stack<>();
/***
 * rightSign存的是每一个入栈的下标
 *  最后变为 11  10  7
 */
Stack<Integer> rightSign = new Stack<>();

核心代码变化:
入栈代码变化:

   for (int i = height.length - 2; i > 1; i--) {
            if (height[i] > rightStack.peek()) {
                rightStack.push(height[i]);
            } else {
                rightStack.push(rightStack.peek());
            }
        }
        for (int i = height.length - 2; i > 1; i--) {
            if (height[i] > rightStack.peek()) {
                rightStack.push(height[i]);
            } 
        }
package com.pf.org.cms.yushui;


import java.util.LinkedList;
import java.util.Stack;

public class DongTai {


    public static int trap(int[] height) {
        /**
         * 因为想存水至少需要3个
         */
        if (height.length <= 2) {
            return 0;
        }
        /***
         * 总存水量
         */
        int maxShui = 0;

        /***
         * 单个格子的存水量
         */
        int oneShui = 0;

        /***
         * maxLeft要存的是从第1个arr[0]到倒数第二个arr[i-1]之间的最大值
         */
        int maxLeft = 0;
        /***
         * rightStack 要存的是从第3个arr[2]到最后一个arr[len-1]之间所有的最大值
         */
        Stack<Integer> rightStack = new Stack<>();
        /***
         * rightSign存的是每一个入栈的下标
         */
        Stack<Integer> rightSign = new Stack<>();

        /**
         * 先放入最后一个
         */
        rightStack.push(height[height.length - 1]);
        rightSign.push(height.length - 1);
        /**
         * 从倒数第二个开始,到正数第三个也就是arr[2]结束
         */
        for (int i = height.length - 2; i > 1; i--) {
            if (height[i] > rightStack.peek()) {
                rightStack.push(height[i]);
                rightSign.push(i);
            }
        }
        /***
         * 最后的一个入栈标志,先谈出
         */
        int rightPop = rightStack.pop();

        /***
         * 因为第一个格子和最后一个格子是存不了水的
         */
        for (int i = 1; i < height.length - 1; i++) {
            if (height[i - 1] > maxLeft) {
                maxLeft = height[i - 1];
            }
            System.out.println(i + "--------" + rightSign.peek());
            if (i == rightSign.peek()) {
                rightSign.pop();
                rightPop = rightStack.pop();
            }
            oneShui = Math.min(maxLeft, rightPop) - height[i];
            if (oneShui < 0) {
                oneShui = 0;
            }
            System.out.println(i + "    " + oneShui);
            maxShui += oneShui;

        }
        return maxShui;

    }

    public static void main(String[] args) {
        int arr[] = new int[]{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1};
        System.out.println(trap(arr));
    }

}

结果分析:

1--------7
1    0
2--------7
2    1
3--------7
3    0
4--------7
4    1
5--------7
5    2
6--------7
6    1
7--------7
7    0
8--------10
8    0
9--------10
9    1
10--------10
10    0
最后结果是:6

力扣统计:

执行用时 :5 ms, 在所有Java提交中击败了48.83%的用户
内存消耗 :36.2 MB, 在所有Java提交中击败了92.01%的用户

猜你喜欢

转载自blog.csdn.net/qq_39455116/article/details/91412880