当青训营遇上码上掘金,码上掘金yyds!攒青豆,单调栈经典应用,附单调栈模板及单调栈系列题目

165 阅读3分钟

最近发现一款在线代码编辑器,名字叫码上掘金,说到轻量代码编辑,我肯定第一时间想到vscode的网页版本,但今天这个和vscode还真就不一样,各有优劣,我真的很喜欢这款在线代码编辑器,它的用户界面美观,操作流畅,是一款非常好用的工具!

image.png 这是他一进去的场景,轻量、深色的背景十分讨喜,个人感觉,这款代码编辑器其实和vscode还是不太一样的,vscode主要是对一个项目进行编写,而码上掘金主要是保存代码片段,我个人理解,你可以拿来保存一些算法模板,例如二分查找模板、并查集模板、线段树模板等,很多算法都是有模板的,理解了之后就不需要重复的敲那些类似的代码了,直接把模板cv上去然后根据题意修改即可了

好的,言归正传,回到我们今天的算法题目:攒青豆

  • 主题 4:攒青豆

    现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)

攒青豆.png

以下为上图例子的解析:

输入:height = [5,0,2,1,4,0,1,0,3]  
输出:17  
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。

作者:青训营官方账号
链接:juejin.cn/post/717498…
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

思路:

看到这题,其实算是很经典单调栈应用题了,我们从前往后遍历与从后往前遍历,我们维护两个数组leftright,其中保存left数组负责保存左边比当前大的下一个元素,而right保存右边下一个更大元素 那么得到leftright之后我们遍历每个元素,对它的left[i]right[i]进行处理就好 具体处理流程,首先接的求出能接到青豆的宽度,再求高度,ans += 高度 * 宽就可以了,当然这其中有个去重的问题,我们用set,用left[i], right[i], height[i]当key来去重

代码

也可以通过码上掘金查看到我的代码奥 攒青豆-单调栈


public class Solution {
    public static void main(String []args) {
        Solution main = new Solution();
        int[] height = new int[]{4,2,0,3,2,5};
        System.out.println(main.saveBeans(height));
    }
    public int saveBeans(int[] height) {
        int ans = 0, n = height.length;
        Deque<Integer> st = new ArrayDeque<>();
        int[] right = new int[n];
        int[] left = new int[n];

        for (int i = n - 1; i >= 0; i--) {
            while (!st.isEmpty() && height[i] >= height[st.peek()]) {
                st.pop();
            }
            right[i] = st.isEmpty() ? i : st.peek();
            st.push(i);
        }
        st.clear();
        for (int i = 0; i < n; i++) {
            while (!st.isEmpty() && height[i] >= height[st.peek()]) {
                st.pop();
            }
            left[i] = st.isEmpty() ? i : st.peek();
            st.push(i);
        }
        Set<List<Integer>> set = new HashSet<>();
        for (int i = 0; i < n; i++) {
            int currHeight = Math.min(height[left[i]], height[right[i]]) - height[i];
            int currWidth = right[i] - left[i] - 1;
            if (set.contains(Arrays.asList(left[i], right[i], height[i]))) continue;
            set.add(Arrays.asList(left[i], right[i], height[i]));

            ans += currHeight * currWidth;
        }
        return ans;
    }
}

单调栈模板

没学过单调栈的同学可以看下这个oi-wiki单调栈 模板这东西,还是需要自己去总结,比如这题,我总结出了这个模板,将来类似的题就可以直接改改拿去用,需要改的地方我在注释上表明了


        Deque<Integer> st = new ArrayDeque<>();
        int[] right = new int[n];
        int[] left = new int[n];

        for (int i = n - 1; i >= 0; i--) {
        // 判断条件
            while (!st.isEmpty() && height[i] >= height[st.peek()]) {
                st.pop();
            }
            // 栈空处理方法
            right[i] = st.isEmpty() ? i : st.peek();
            st.push(i);
        }
        st.clear();
        for (int i = 0; i < n; i++) {
        // 判断条件
            while (!st.isEmpty() && height[i] >= height[st.peek()]) {
                st.pop();
            }
            // 栈空处理方法
            left[i] = st.isEmpty() ? i : st.peek();
            st.push(i);
        }

单调栈相关题目