攒青豆 | 「青训营 X 码上掘金」主题创作活动

72 阅读2分钟

当青训营遇上码上掘金,利用掘金社区提供的在线coding平台码上掘金完成代码的编写和测试。

攒青豆

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

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

方法1: 双指针法

思路: 首先,双指针法是按照列来累计青豆数量的 两个指针同时从两端出发,由于可能出现左端与右端可能出现,高度为零的情况则在移动是首先将两指针移动到有效位置。下一步,由于装青豆和接雨水等都属于木桶效应问题,低的一端决定了中间的青豆的高度,则从低的一端向中间移动,将此端点存为这一次的最高高度,当移动到高于此高度的点时,将该侧的最高高度更新,并且与另一侧的最高点比较,同样是低的一端移动,两侧最高点中较低的一端决定了中间的青豆多少,这样最后两侧移动到错开后,则可以得出攒青豆的数量。 代码:

int bean(vector<int>& height) {
    int result = 0;
    int l = 0, r = height.size()-1;
    while(height[l]==0 && l<r) l++;
    while(height[r]==0 && l<r) r--;
    if(l>=r) return result;
    int leftmax = height[l];
    int rightmax = height[r];
    while(l < r) {
        if(leftmax<=rightmax) {
            l++;
            if(height[l]>leftmax) {
                leftmax=height[l];
                continue;
            }
            result += leftmax - height[l];
        } else {
            r--;
            if(height[r]>rightmax) {
                rightmax=height[r];
                continue;
            }
            esult += rightmax - height[r];
        }
    }
    return result;
}

方法2: 单调栈

思路: 单调栈的思路与括号匹配较为相似。每次匹配出一对括号(找到对应的一堵墙),就计算这两堵墙中的我们用栈保存每堵墙。当遍历墙的高度的时候,如果当前高度小于栈顶的墙高度,说明这里会有积水,我们将墙的高度的下标入栈。如果当前高度大于栈顶的墙的高度,说明之前的积水到这里停下,我们可以计算下有多少积水了。计算完,就把当前的墙继续入栈,作为新的积水的墙。总体上为按行计算豆子数量。

代码:

int trap(vector<int>& height) { 
    stack<int> st; 
    st.push(0); 
    int sum = 0; 
    for (int i = 1; i < height.size(); i++) { 
        while (!st.empty() && height[i] > height[st.top()]) { 
            int mid = st.top(); 
            st.pop(); 
            if (!st.empty()) { 
                int h = min(height[st.top()], height[i]) - height[mid]; 
                int w = i - st.top() - 1; 
                sum += h * w; 
            } 
        } 
        st.push(i); 
    } 
    return sum; 
} 

代码地址

攒绿豆-码上掘金