当青训营遇上码上掘金
主题题目描述
现有 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数组的长度,无论是计算, 还是最后统计答案,我们都只需要对数组进行一次遍历即可
空间复杂度:,解法过程需要数组以及数组,数组长度与给出的height数组相同
双指针做法
时间复杂度:,双指针分别从数组两端向中间对数组进行一次遍历,双指针移动次数不会超过
空间复杂度:,只需要常数级的额外几个变量
解题代码
初始做法
C++代码:
class Solution {
public:
int bean(vector<int>& height) {
int n = height.size(), ans = 0;
vector<int> lmax(n + 2, 0), rmax(n + 2, 0);
for(int i = 0; i < n; i++) //计算左端最大值
if(i != 0)
lmax[i] = max(lmax[i - 1], height[i - 1]);
for(int i = n - 1; i >= 0; i--) //计算右端最大值
if(i != n - 1)
rmax[i] = max(rmax[i + 1], height[i + 1]);
for(int i = 0; i < n; i++) //统计每列的存豆量
ans += max(0, min(lmax[i], rmax[i]) - height[i]);
return ans;
}
};
Go语言代码:
func max(a int, b int) int {
if a > b {
return a
}
return b
}
func min(a int, b int) int {
if a > b {
return b
}
return a
}
func bean(height []int) int {
lmax := make([]int, len(height))
rmax := make([]int, len(height))
for i := 0; i < len(height); i++ {
if i != 0 {
lmax[i] = max(lmax[i - 1], height[i - 1])
}
}
for i := len(height) - 1; i >= 0; i-- {
if i != len(height) - 1 {
rmax[i] = max(rmax[i + 1], height[i + 1])
}
}
ans := 0
for i := 0; i < len(height); i++ {
ans += max(0, min(lmax[i], rmax[i]) - height[i])
}
return ans
}
双指针做法
C++代码:
class Solution {
public:
int bean(vector<int>& height) {
int ans = 0;
int lmax = 0, rmax = 0, l = 0, r = height.size() - 1;
while(l <= r)
{
if(lmax < rmax)
{
lmax = max(lmax, height[l]);
ans += lmax - height[l];
l++;
}
else
{
rmax = max(rmax, height[r]);
ans += rmax - height[r];
r--;
}
}
return ans;
}
};
Go语言代码:
func max(a int, b int) int {
if a > b {
return a
}
return b
}
func bean(height []int) int {
var l, r int = 0, len(height) - 1
var lmax, rmax, ans int
for l <= r {
if lmax < rmax {
lmax = max(lmax, height[l])
ans += lmax - height[l]
l++
} else {
rmax = max(rmax, height[r])
ans += rmax - height[r]
r--
}
}
return ans
}