当青训营遇上码上掘金
1. 主题介绍
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
这道题的原型实际上是力扣经典接雨水问题,也是面试常考题。
2. 解法思路
2.1 按列求
求每一列的水,我们只需要关注当前列,以及左边最高的墙,右边最高的墙就够了。装水的多少取决于左右两边较矮的墙。
代码如下:
public int trap1(int[] height) {
int sum = 0;
for (int i = 1; i < height.length - 1; i++) {
int max_left = 0;
for (int j = i - 1; j >= 0; j--) {
if (height[j] > max_left) {
max_left = height[j];
}
}
int max_right = 0;
for (int j = i + 1; j < height.length; j++) {
if (height[j] > max_right) {
max_right = height[j];
}
}
int min = Math.min(max_left, max_right);
if (min > height[i]) {
sum += (min - height[i]);
}
}
return sum;
}
时间复杂度:O(n²)。
空间复杂度:O(1)。
2.2 动态规划
在2.1的解法中,对于每一列求其左右最高墙时,都是重新遍历一遍所有高度,这里可以提前计算每一列左右最高墙的高度并保存,以进行优化。
使用max_left [i] 代表第 i 列左边最高的墙的高度,max_right[i] 代表第 i 列右边最高的墙的高度。
max_left [i] = Max(max_left [i-1],height[i-1]);
max_right[i] = Max(max_right[i+1],height[i+1])。
完整代码如下:
public int trap2(int[] height) {
int sum = 0;
int[] max_left = new int[height.length];
int[] max_right = new int[height.length];
for (int i = 1; i < height.length - 1; i++)
max_left[i] = Math.max(max_left[i - 1], height[i - 1]);
for (int i = height.length - 2; i >= 0; i--)
max_right[i] = Math.max(max_right[i + 1], height[i + 1]);
for (int i = 1; i < height.length - 1; i++) {
int min = Math.min(max_left[i], max_right[i]);
if (min > height[i]) sum = sum + (min - height[i]);
}
return sum;
}
时间复杂度:O(n)。
空间复杂度:O(n)。
2.3 双指针
max_left [ i ] 和 max_right [ i ] 数组中的元素我们其实只用一次,然后就再也不会用到了。
public int trap3(int[] height) {
int ans = 0;
int left = 0, right = height.length - 1;
int left_max = 0, right_max = 0;
while (left < right) {
left_max = Math.max(left_max, height[left]);
right_max = Math.max(right_max, height[right]);
if (height[left] < height[right]) ans += left_max - height[left++];
else ans += right_max - height[right--];
}
return ans;
}
时间复杂度: O(n)。
空间复杂度: O(1)。
3. 码上掘金
我的码上掘金不知道怎么调成后端语言,试了所有的按钮都不行,后面复制了一个别人的后端仓库,然后改成自己的代码。(如果你们不知道怎么调成后端语言也可以复制我的,知道的话可以在评论区评论一下)