栈
数组
双指针
动态规划
单调栈
题目描述
给定 n
个非负整数表示每个宽度为 1
的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:
输入: height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6
解释: 上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例 2:
输入: height = [4,2,0,3,2,5]
输出: 9
提示:
n == height.length
1 <= n <= 2 * 104
0 <= height[i] <= 105
解法
方法一:动态规划
我们定义 $left[i]$ 表示下标 $i$ 位置及其左边的最高柱子的高度,定义 $right[i]$ 表示下标 $i$ 位置及其右边的最高柱子的高度。那么下标 $i$ 位置能接的雨水量为 $\min(left[i], right[i]) - height[i]$。我们遍历数组,计算出 $left[i]$ 和 $right[i]$,最后答案为 $\sum_{i=0}^{n-1} \min(left[i], right[i]) - height[i]$。
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为数组的长度。
Python3 Java C++ Go TypeScript Rust C# PHP
class Solution :
def trap ( self , height : List [ int ]) -> int :
n = len ( height )
left = [ height [ 0 ]] * n
right = [ height [ - 1 ]] * n
for i in range ( 1 , n ):
left [ i ] = max ( left [ i - 1 ], height [ i ])
right [ n - i - 1 ] = max ( right [ n - i ], height [ n - i - 1 ])
return sum ( min ( l , r ) - h for l , r , h in zip ( left , right , height ))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 class Solution {
public int trap ( int [] height ) {
int n = height . length ;
int [] left = new int [ n ] ;
int [] right = new int [ n ] ;
left [ 0 ] = height [ 0 ] ;
right [ n - 1 ] = height [ n - 1 ] ;
for ( int i = 1 ; i < n ; ++ i ) {
left [ i ] = Math . max ( left [ i - 1 ] , height [ i ] );
right [ n - i - 1 ] = Math . max ( right [ n - i ] , height [ n - i - 1 ] );
}
int ans = 0 ;
for ( int i = 0 ; i < n ; ++ i ) {
ans += Math . min ( left [ i ] , right [ i ] ) - height [ i ] ;
}
return ans ;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 class Solution {
public :
int trap ( vector < int >& height ) {
int n = height . size ();
int left [ n ], right [ n ];
left [ 0 ] = height [ 0 ];
right [ n - 1 ] = height [ n - 1 ];
for ( int i = 1 ; i < n ; ++ i ) {
left [ i ] = max ( left [ i - 1 ], height [ i ]);
right [ n - i - 1 ] = max ( right [ n - i ], height [ n - i - 1 ]);
}
int ans = 0 ;
for ( int i = 0 ; i < n ; ++ i ) {
ans += min ( left [ i ], right [ i ]) - height [ i ];
}
return ans ;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14 func trap ( height [] int ) ( ans int ) {
n := len ( height )
left := make ([] int , n )
right := make ([] int , n )
left [ 0 ], right [ n - 1 ] = height [ 0 ], height [ n - 1 ]
for i := 1 ; i < n ; i ++ {
left [ i ] = max ( left [ i - 1 ], height [ i ])
right [ n - i - 1 ] = max ( right [ n - i ], height [ n - i - 1 ])
}
for i , h := range height {
ans += min ( left [ i ], right [ i ]) - h
}
return
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14 function trap ( height : number []) : number {
const n = height . length ;
const left : number [] = new Array ( n ). fill ( height [ 0 ]);
const right : number [] = new Array ( n ). fill ( height [ n - 1 ]);
for ( let i = 1 ; i < n ; ++ i ) {
left [ i ] = Math . max ( left [ i - 1 ], height [ i ]);
right [ n - i - 1 ] = Math . max ( right [ n - i ], height [ n - i - 1 ]);
}
let ans = 0 ;
for ( let i = 0 ; i < n ; ++ i ) {
ans += Math . min ( left [ i ], right [ i ]) - height [ i ];
}
return ans ;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 impl Solution {
#[allow(dead_code)]
pub fn trap ( height : Vec < i32 > ) -> i32 {
let n = height . len ();
let mut left : Vec < i32 > = vec! [ 0 ; n ];
let mut right : Vec < i32 > = vec! [ 0 ; n ];
left [ 0 ] = height [ 0 ];
right [ n - 1 ] = height [ n - 1 ];
// Initialize the left & right vector
for i in 1 .. n {
left [ i ] = std :: cmp :: max ( left [ i - 1 ], height [ i ]);
right [ n - i - 1 ] = std :: cmp :: max ( right [ n - i ], height [ n - i - 1 ]);
}
let mut ans = 0 ;
// Calculate the ans
for i in 0 .. n {
ans += std :: cmp :: min ( left [ i ], right [ i ]) - height [ i ];
}
ans
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 public class Solution {
public int Trap ( int [] height ) {
int n = height . Length ;
int [] left = new int [ n ];
int [] right = new int [ n ];
left [ 0 ] = height [ 0 ];
right [ n - 1 ] = height [ n - 1 ];
for ( int i = 1 ; i < n ; ++ i ) {
left [ i ] = Math . Max ( left [ i - 1 ], height [ i ]);
right [ n - i - 1 ] = Math . Max ( right [ n - i ], height [ n - i - 1 ]);
}
int ans = 0 ;
for ( int i = 0 ; i < n ; ++ i ) {
ans += Math . Min ( left [ i ], right [ i ]) - height [ i ];
}
return ans ;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 class Solution {
/**
* @param integer[] $height
* @return integer
*/
function trap($height) {
$n = count($height);
if ($n == 0) {
return 0;
}
$left = 0;
$right = $n - 1;
$leftMax = 0;
$rightMax = 0;
$ans = 0;
while ($left < $right) {
if ($height[$left] < $height[$right]) {
if ($height[$left] > $leftMax) {
$leftMax = $height[$left];
} else {
$ans += $leftMax - $height[$left];
}
$left++;
} else {
if ($height[$right] > $rightMax) {
$rightMax = $height[$right];
} else {
$ans += $rightMax - $height[$right];
}
$right--;
}
}
return $ans;
}
}