「青训营 X 码上掘金」主题 4——攒青豆

51 阅读1分钟

当青训营遇上码上掘金

主题介绍

攒青豆

题目描述

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

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

思路解析

根据题目可以得出,能接住多少青豆取决于凹槽两边柱子的高度,并且以矮的柱子为准。

第一步,本题使用一个h数组表示柱子的高度,先处理l数组和r数组,l数组表示最靠近当前元素的左边的元素下标,同理r数组最靠近当前元素的由边的元素下标。

第二步,处理完后通过r数组和l数组找到能存放青豆的高度和宽度,然后加上这一单位的青豆,积累所有的青豆,就能得到最终答案。

代码实现

public static Integer Solve(int[] h) {
    Integer n = h.length;
    Integer res = 0;
    Integer l[] = new Integer[n];
    Integer r[] = new Integer[n];
    //因为需要去重,所以我们这里使用set来去重
    Set<List<Integer>> set = new HashSet<>();
    Deque<Integer> st = new ArrayDeque<>();
    //处理l数组
    for (int i = 0; i < n; i++) {
        while (!st.isEmpty() && h[st.peek()] <= h[i]) st.pop();
        if (st.isEmpty()) l[i] = i;
        else l[i] = st.peek();
        st.push(i);
    }
    st.clear();
    //处理r数组
    for (int i = n - 1; i >= 0; i--) {
        while (!st.isEmpty() && h[st.peek()] <= h[i]) st.pop();
        if (st.isEmpty()) r[i] = i;
        else r[i] = st.peek();
        st.push(i);
    }
    for (int i = 0; i < n; i++) {
        //因为能够接受到的青豆取决于两边较小的柱子,所以使用min找到较小值
        Integer indexH = Math.min(h[l[i]], h[r[i]]) - h[i];
        Integer indexW = r[i] - l[i] - 1;
        if (!((HashSet<?>) set).contains(Arrays.asList(l[i], r[i], h[i]))) {
            res += indexW * indexH;
            set.add(Arrays.asList(l[i], r[i], h[i]));
        }
    }
    return res;