当青训营遇上码上掘金,你会发现
他们确实遇上了。
主题4 攒青豆
开发环境
- 开发语言:Java
- 代码平台:码上掘金
题目描述
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
我的解答
思路分析
首先我们先思考一个问题:
-
如何判断某个位置是否可以存放青豆?
答案是:这个位置的左右两边都有严格大于这个位置高度的柱子。
那么再思考一个问题:
-
如何判断某个位置所能存放的青豆数?
答案是:在满足第一个问题的答案的条件下,某个位置所能存放的青豆数量:
这个位置左右两个侧中最高柱子中高度值最小的那个,减去这个位置柱子的高度。(值为0的位置也算柱子,看成高度为0的柱子)
所以,对于每个位置i,我们需要求得其左侧柱子中最高柱子的高度,以及右侧柱子中最高柱子的高度。该位置所能存放的青豆数即为这两个值中的最小值减去该位置柱子高度值。最后将所有能存放青豆的位置所能存放的青豆数相加即得到最后的结果。
代码实现
public class Main {
static public int trap(int[] height){
int n = height.length;
//max[i][0]:左最大值,max[i][1]:右最大值
int[][] max = new int[n][2];
//需要给边界设定上值,第0个左边肯定是自己最大,第n-1个的右边必然是自己最大
max[0][1] = max[0][0] = height[0];
max[n-1][0] = max[n-1][1] = height[n-1];
//我们依次求取该位置左侧中的最高柱子值
for (int i = 1; i < height.length; i++) {
max[i][0] = Math.max(max[i-1][0],height[i]);
}
//再依次求取该位置右侧最高柱子值
for(int i = n-2;i>=0;i--){
max[i][1] = Math.max(max[i+1][1],height[i]);
}
//最后求该位置接住青豆值,某一个位置能接多少单位的青豆,等于该位置左右两侧最高柱子中
// 相对较小的那一侧最高柱子值-该位置柱子高度
int total = 0;
for (int i = 0; i < n; i++) {
total += Math.min(max[i][0],max[i][1]) - height[i];
}
return total;
}
// 测试
public static void main(String []args) {
int[] height = new int[]{5,0,2,1,4,0,1,0,3};
System.out.println("可接得青豆数为:"+trap(height));
}
}
复杂度分析
时间复杂度:
分别使用了三次循环,每次数量级都为n,所以整体的时间复杂度为O(n)。
空间复杂度:
使用了二维数组,在原来的数组上多了一维来保存额外信息,所以空间复杂度为O(n)。
总结
这个题目看到时就有了这个思路,然后赶时间就先写上来了,后来又有了别的思路:
简单来说就是以所有柱子中的最大值为边及柱子索引最大值为边,构造一个矩形,然后能够存放的青豆数就是该矩形面积-空气面积-柱子面积。(其中空气面积为矩形中所有柱子边缘围成的部分之外的面积)这样这个题目就变成了一个数学题了。
哈哈,只是有这么一个想法,还没来得及实现。
文章中的代码或者思路有什么问题和错误的,望指正!🤞