当青训营遇上码上掘金

47 阅读2分钟

我是一名在校大二的学生,很荣幸的参加本次青训营的# 「青训营 X 码上掘金」主题创作活动

1 ).问题描述

攒青豆

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

screenshot-20230213-163258.png

以下为上图例子的解析:

输入:height = [5,0,2,1,4,0,1,0,3]

输出:17

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

2) .算法思路

使用单调栈找到每根柱子左边第一个比它高的位置,把两根柱子之间的青豆数累加起来,栈内元素是成递减的顺序保存的。

  • 首先比较当前栈顶元素是否小于当前柱子高度,如果小于栈顶就继续入栈,否则就要找到把栈弹出到第一个比当前柱子高的位置,栈内元素存的数组下标位置,所以可以通过当前下标值与之前的值相减得到宽度差。
  • 使用Last变量记录上一个弹出栈顶的元素高度,因为可以计算两个柱子之间的高度差,每次弹出柱子都要更新一次Last。
  • 最后判断栈是否为空,不空的话需要加上左边柱子比当前柱子高的之间大小。

3).代码示例

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        ArrayList list = new ArrayList<>();
        while (sc.hasNextInt()) {
            list.add(sc.nextInt());
        }
        //请输入ok表示输入结束
        int height[] = new int[list.size()];
        for (int i = 0; i < height.length; i++) {
            height[i] = (int) list.get(i);
        }
        System.out.println(qingdou(height));
    }

    private static int qingdou(int[] nums) {
        Stack<Integer> stack = new Stack<>();
        int ans = 0;
        for (int i = 0; i < nums.length; i++) {
            int last = 0; 
            while (!stack.empty() && nums[stack.peek()] <= nums[i]) {
                ans += (nums[stack.peek()] - last) * (i - stack.peek() - 1);
                last = nums[stack.peek()];
                stack.pop();
            }
            if (!stack.empty()) {
                ans += (nums[i] - last) * (i - stack.peek() - 1);
            }
            stack.push(i);
        }
        return ans;
    }
}

4).效果展示

screenshot-20230213-164140.png