当青训营遇上码上掘金,非常高兴可以有机会参加青训营活动。这篇文章是针对 「青训营 X 码上掘金」主题创作活动中后端部分主题四创作的文章,主要内容包括题目描述,题目分析,算法复杂度分析还有代码实现。现在就让我们开始吧~
题目描述
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
题目分析
这是一道非常典型的动态规划题目,我们用i来表示下标,n来表示height的长度。
创建两个长度为n的数组数组left和right,来分别表示柱子左边和右边能接住最多青豆的数量。
对于每个i,我们可以从前到后扫描(正向遍历)每个柱子相对于右侧能接住青豆最大的数量,用right[i]表示;从后到前扫描(反向遍历)每个柱子相对于左侧能接住青豆最大的数量,用left[i]表示。
每个i能接住的青豆数量等于min(left[i],right[i])−height[i]。遍历每个下标可以得到总共能接住的青豆数量。
算法复杂度分析
时间复杂度
总共遍历三次数组,时间复杂度为O(n)。
空间复杂度
需要创建两个长度为n的数组,空间复杂度为O(n)。
代码实现
java
class Solution {
public int trap(int[] height) {
int n = height.length, res = 0;
int[] left = new int[n + 1];
int[] right = new int[n + 1];
for(int i = 0, preMax = height[0]; i < n; i++){
preMax = Math.max(preMax, height[i]);
right[i] = preMax;
}
for(int i = n-1, preMax = height[n-1]; i >= 0; i--){
preMax = Math.max(preMax, height[i]);
left[i] = preMax;
}
for(int i = 0; i < n; i++){
res += Math.min(left[i], right[i]) - height[i];
// System.out.println(i + " " + left[i] + " " + right[i] + " " + height[i]);
// System.out.println(res);
}
return res;
}
}