当青训营遇上码上掘金
题目描述
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
输入
[5,0,2,1,4,0,1,0,3]
输出
17
解题思路
第一眼看到,这不是大名鼎鼎的接雨水嘛,leetcode 42 题,就是更改了文案,这里我们就不再赘述了,直接上代码写思路。
版本一 暴力即是美学
首先我们来看一下暴力解法,我们可以遍历每个位置,然后分别向左和向右遍历,找到左右两边的最大值,然后取两个最大值的最小值,减去当前位置的高度,就是当前位置能接的雨水量,然后将所有位置的雨水量相加,就是最终的结果。
public int trap(int[] height) {
int ans = 0;
int size = height.length;
for (int i = 1; i < size - 1; i++) {
int max_left = 0, max_right = 0;
//
for (int j = i; j >= 0; j--) { //Search the left part for max bar size
max_left = Math.max(max_left, height[j]);
}
for (int j = i; j < size; j++) { //Search the right part for max bar size
max_right = Math.max(max_right, height[j]);
}
ans += Math.min(max_left, max_right) - height[i];
}
return ans;
}
复杂度分析
时间复杂度:O(n^2)。两个 for 循环。
空间复杂度:O(1)。使用了常数个变量。
版本二 优化
上面的代码是暴力解法,我们可以使用动态规划的思想,将每个位置的左右最大值都计算出来,然后再遍历一次,这样就可以将时间复杂度降低到 O(n)。
public int trap(int[] height) {
if (height == null || height.length == 0) {
return 0;
}
int ans = 0;
int size = height.length;
int[] left_max = new int[size];
int[] right_max = new int[size];
left_max[0] = height[0];
for (int i = 1; i < size; i++) {
left_max[i] = Math.max(height[i], left_max[i - 1]);
}
right_max[size - 1] = height[size - 1];
for (int i = size - 2; i >= 0; i--) {
right_max[i] = Math.max(height[i], right_max[i + 1]);
}
for (int i = 1; i < size - 1; i++) {
ans += Math.min(left_max[i], right_max[i]) - height[i];
}
return ans;
}
复杂度分析
时间复杂度:O(n)。两个 for 循环。
空间复杂度:O(n)。使用了两个数组。
版本三 双指针
上面的解法中,我们使用了两个数组,分别存储了每个位置的左右最大值,其实我们可以使用两个指针,分别指向当前位置的左右两边,然后再遍历一次,这样就可以将空间复杂度降低到 O(1)。
public int trap(int[] height) {
int left = 0, right = height.length - 1;
int ans = 0;
int left_max = 0, right_max = 0;
while (left < right) {
if (height[left] < height[right]) {
if (height[left] >= left_max) {
left_max = height[left];
} else {
ans += (left_max - height[left]);
}
++left;
} else {
if (height[right] >= right_max) {
right_max = height[right];
} else {
ans += (right_max - height[right]);
}
--right;
}
}
return ans;
}
复杂度分析
时间复杂度:O(n)。一次遍历。
空间复杂度:O(1)。使用了常数个变量。