当青训营遇上码上掘金
主题介绍
攒青豆
题目描述
主题 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;