直方图的水量 | 刷题打卡

105 阅读1分钟

本文正在参与掘金团队号上线活动,点击 查看大厂春招职位

一、题目描述:

image.png

二、思路分析:

暴力解法

很显然,我们容易想到木桶效应。每个位置能盛的水由这个位置左右两边较短的边界决定,因此我们可以很快的写出一种暴力的方法。

  • 时间复杂度: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;
    }

四、总结:

空间换取时间是比较常用的方法,我们可以从暴力解法入手,观察是否能用空间换取时间的办法得到效率上的提升。