当青训营遇上码上掘金,利用掘金社区提供的在线coding平台码上掘金完成代码的编写和测试。
攒青豆
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入: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;
}