本文正在参与掘金团队号上线活动,点击 查看大厂春招职位
一、题目描述:
二、思路分析:
暴力解法
很显然,我们容易想到木桶效应。每个位置能盛的水由这个位置左右两边较短的边界决定,因此我们可以很快的写出一种暴力的方法。
- 时间复杂度:O(N^2),这里 N 是数组的长度。
- 空间复杂度:O(1),使用到的临时变量的个数是常数。
动态规划
既然时间复杂度比较高,我们可以考虑空间换时间。因为我们在暴力解那里是现算了每个位置的左右两边的最大值,所以我们可以提前遍历一遍数组,存储下每个位置的左边最大值和右边最大值。达到用空间换取时间的效果,从而提升速度。 PS:暂且就归为动态规划吧,我做的时候没这么想[狗头]
- 时间复杂度:O(N),这里 N 是数组的长度。
- 空间复杂度:O(N),使用到的临时变量的个数是常数。
双指针
其实这道题还有空间复杂度O(1)的解,但是一般比较难想到。想学习的同学自己去看一下文章吧
三、AC 代码:
//暴力解
class Solution {
/**
* @param Integer[] $height
* @return Integer
*/
function trap($height) {
$res = 0;
$n = count($height);
for ($i = 1; $i < $n-1; $i++) {
$l_max = $r_max = 0;
for ($j = 0; $j <= $i; $j++) {
$l_max = max($l_max, $height[$j]);
}
for ($j = $i; $j < $n; $j++) {
$r_max = max($r_max, $height[$j]);
}
$temp = (min($r_max, $l_max) - $height[$i]);
$res+=$temp;
}
return $res;
}
}
//优化后的解,采用空间换取时间
function trap($height) {
$len_h = count($height);
if ($len_h < 3) {
return 0;
}
$ret = 0;
$leftMax = array_fill(0, $len_h, 0);
$rightMax = array_fill(0, $len_h, 0);
$l = $height[0];
for ($i = 1; $i < $len_h; $i++) {
$l = max($height[$i], $l);
$leftMax[$i] = $l;
}
$r = $height[$len_h - 1];
for ($i = $len_h - 1; $i >= 0; $i--) {
$r = max($height[$i], $r);
$rightMax[$i] = $r;
}
for ($i = 1; $i < $len_h - 1; $i++) {
$t = (min($leftMax[$i], $rightMax[$i]) - $height[$i]);
$ret += $t;
}
return $ret;
}
四、总结:
空间换取时间是比较常用的方法,我们可以从暴力解法入手,观察是否能用空间换取时间的办法得到效率上的提升。