文章目录
一、前言
接雨水,这道题我在大学的时候就听说这道题是力扣的难题,但是一直没有做过。
这几天在网上偶然看到关于这道题的文章,于是去学了学这两题的解题思路,故写下这篇博客记录记录。
力扣链接:力扣42. 接雨水
二、前后缀分解
前后缀分解的思路就是把每一个下标看作一个桶,当前下标的值看作通底高度,这个桶能装多少水,取决于桶的左边的最大值、右边最大值以及桶的高度。
那能装多少水,这个取决于左右最大高度的最小值,以及桶底的高度
比如下图这个桶,左边最大值为2,右边最大值为3,桶底高度为0,所以这个桶能装单位为2的水。
再比如,下面这个桶,左边最大高度为2,右边最大高度为3,桶底高度为1,那么能装单位为1的水。
这个思路需要两个数组辅助实现,数组A负责存放当前下标对应的左边桶高度的最大值,数组B对应存放的是右边桶高度的最大值。
java
class Solution {
public int trap(int[] height) {
int result = 0;
// 左边最大值
int[] larr = new int[height.length];
// 右边最大值
int[] rarr = new int[height.length];
for (int i = 1; i < height.length; i++) {
larr[i] = Math.max(height[i - 1], larr[i - 1]);
}
for (int i = height.length - 2; i >= 0 ; i --) {
rarr[i] = Math.max(height[i + 1], rarr[i + 1]);
}
// 左边最大 右边最大值取最小值,然后再再减去自身高度,就是能装多少水的容量
for (int i = 0; i < height.length; i++) {
int sum = Math.min(larr[i], rarr[i]) - height[i];
if (sum > 0){
result += sum;
}
}
return result;
}
}
时间复杂度:O(n)
,这里遍历了三次height
数组,对应的时间复杂度是O(3n)
,也就是O(n)
。
空间复杂度:O(n)
,额外申请了两个长度为n
的数组,所以空间复杂度为O(n)
.
三、双指针
对于上面的解法,时间复杂度肯定是不能再降低了,因为要找出所有能接多少雨水,肯定要都遍历一遍,故时间复杂度O(n)
是最小的时间复杂度了。
那么只好想办法降低空间复杂度了。
这里需要明确一个点,就是这个桶能接多少雨水,取决于左右边最小的那个值
这里需要分类讨论一下:
对于某一点上的一个桶,知道这个桶左边的最大值(A),同时知道右边某一个区间中的最大值(B)
A < B
,那么当前位置能接多少水,就取决于A,和B没有关系,接的雨水 = A - 桶底高度
,就可以计算当前位置能接多少水,下面左边位置可以往后移动一个单位A > B
,那么当前位置能接多少水,就取决于B,和A没有关系,接的雨水 = B - 桶底高度
,- 就可以计算当前位置能接多少水,下面左边位置可以往前移动一个单位
A = B
,取A 还是 B 都没关系。
java
public int trap(int[] height) {
int result = 0;
int l = 0, r = height.length - 1;
int preMax = 0, sufMax = 0;
while (l <= r){
preMax = Math.max(preMax, height[l]);
sufMax = Math.max(sufMax, height[r]);
if (preMax < sufMax){
result += preMax - height[l];
l ++;
}else {
result += sufMax - height[r];
r --;
}
}
return result;
}
时间复杂度:O(n)
,这里遍历了一次height
数组,也就是O(n)
。
空间复杂度:O(1)
,没有额外申请空间,只用了额外变量。