当青训营遇上码上掘金_主题四

69 阅读2分钟

当青训营遇上码上掘金

选择第四个主题,即“攒青豆”

主题四————攒青豆

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

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

根据题目可知,需要用单调栈来解决这个问题。

单调栈分单调递增栈和单调递减栈,之所以选择单调递减栈,是因为

  • 根据题目的理解,当找到一根比前面高的柱子,就可以计算接到的青豆单位数
  • 所以需要使用单调递减栈。

维护一个单调栈,单调栈存储的是下标,满足从栈底到栈顶的下标对应的数组height中的元素递减。

在入栈的时候需要对更低的柱子入栈

当出现高于栈顶的柱子,就可以对前面柱子进行结算,计算之后出栈。

代码具体如下:

#include<bits/stdc++.h>
using namespace std;
int main() {
    int ans = 0;
    int m[10] =  {5,0,2,1,4,0,1,0,3};
    vector<int> height(m,m+9);
    stack<int> st;
    for (int i = 0; i < height.size(); i++)
    {
        while (!st.empty() && height[st.top()] < height[i])
        {
            int cur = st.top();
            st.pop();
            if (st.empty()) break;
            int l = st.top();
            int r = i;
            int h = min(height[r], height[l]) - height[cur];
            ans += (r - l - 1) * h;
        }
        st.push(i);
    }
  cout<<ans<<endl;
  return 0;
}

单调栈知识点补充:

何为单调栈

栈内元素非递增或者非递减。另一种说法是从栈底到栈顶递增或者递减。在很多情况下,可能会出现相同的数字元素,所以称之为非递增或者非递减栈比递增、递减栈更合适。

显而易见,从单调栈的这种结构很容易联想到,在算法中,合理运用单调栈,能够将O(n^2)的时间复杂度优化到O(n),这就是技巧。相对的,空间复杂度会增加,因为需要动态维护一个栈。这里需要明白一点,算法里面,都是时间和空间的取舍,所谓的时空间转换指的就是这个,所以要根据具体场景去选择。

  • 单调递增栈:单调递增栈就是从栈底到栈顶数据是从大到小
  • 单调递减栈:单调递减栈就是从栈底到栈顶数据是从小到大

参考引用: 单调栈