当青训营遇上码上掘金 | 青训营

47 阅读2分钟

主题介绍

攒青豆

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

image.png

以下为上图例子的解析:

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

思路解析

01. 普通解法

分别向左右遍历一遍,找到左右的最大数,然后再遍历一遍求和所有点的可以攒青豆的总数。

02. 双指针解法

通过双指针法,当左边最大值小于右边最大值时,就坐标往右继续遍历,并将左边这个坐标的可以攒的青豆加入到总数中;当左边最大值大于右边最大值时,就坐标往左继续遍历,并将左边这个坐标的可以攒的青豆加入到总数中。

03. 栈的应用

用栈来跟踪可能攒的青豆的最长的条形块。使用栈就可以在一次遍历内完成计算。

我们在遍历数组时维护一个栈。如果当前的条形块小于或等于栈顶的条形块,我们将条形块的索引入栈,意思是当前的条形块被栈中的前一个条形块界定。如果我们发现一个条形块长于栈顶,我们可以确定栈顶的条形块被当前条形块和栈的前一个条形块界定,因此我们可以弹出栈顶元素并且累加答案。

代码实现

01. 普通解法


int trap(vector<int>& height)
{
    int ans = 0;
    int size = height.size();
    for (int i = 1; i < size - 1; i++) {
        int max_left = 0, max_right = 0;
        for (int j = i; j >= 0; j--) { 
            //Search the left part for max bar size
            max_left = max(max_left, height[j]);
        }
        for (int j = i; j < size; j++) { 
            //Search the right part for max bar size
            max_right = max(max_right, height[j]);
        }
        ans += min(max_left, max_right) - height[i];
    }
    return ans;
}

02. 双指针解法

int trap(vector<int> &height) {
    int left = 0, right = height.size() - 1;
    int ans = 0;
    int left_max = 0, right_max = 0;
    while (left < right) {
        if (height[left] < height[right]) {
            height[left] >= left_max ? (left_max = height[left]) : ans += (left_max - height[left]);
            ++left;
        } else {
            height[right] >= right_max ? (right_max = height[right]) : ans += (right_max - height[right]);
            --right;
        }
    }
    return ans;
}

03. 栈的应用 — 单调栈

int qingdou(int[] w){
        Stack<Integer> stack = new Stack<>();
        int res = 0;
        //单调栈
        for(int i = 0; i < w.length; i++){            
            int last = 0; //上一个栈顶元素
            while(!stack.empty() && w[stack.peek()] <= w[i]){
                res += (w[stack.peek()] - last) * (i - stack.peek() - 1);
                last = w[stack.peek()];
                stack.pop();
            }
            if(!stack.empty()) {
                res += (w[i] - last) * (i - stack.peek() - 1);
            }
            stack.push(i);
        }
        return res;
    }

  • 完整代码已上传至码上掘金平台