Leetcode 之 PHP 解析 (42. Trapping Rain Water)

Remember發表於2020-01-10

Leetcode之PHP解析(42. Trapping Rain Water)

題目介紹

這道題挺有意思的,給定一個非負數的每個寬度為1的柱形圖,問你下雨天能接多少雨水。例題中給定的陣列能接的總數為6,即圖中藍色部分。

題目分析

我們先來隨便舉個例子吧。例如示例中給出的陣列第6位(也就是索引位置5)高度為0,此時這個位置能盛的水是2。這個2是咋麼算出來的呢。從當前位置往它的左邊查詢,查出最高的水位,即索引3(值為2)。從當前位置往右邊找出它的最高位,即索引位置7(值為3),然後取他們中的最小值高度 min(2,3) 減去當前位置的高度(0)=2。為什麼取的是兩者的最小值呢。很簡單的道理,兩邊之間能盛的水的高度必然會和其中一邊高度持平的,再高就溢位了。

程式碼實現

 /**
 * @param Integer[] $height
 * @return Integer
 */
function trap($height)
{
    $res = 0;
    $size = count($height);
    for ($i = 1; $i < $size - 1; $i++) {
        $left = 0;
        $right = 0;
        for ($j = $i; $j >= 0; $j--) {
            $left = max($left, $height[$j]);
        }
        for ($j = $i; $j < $size; $j++) {
            $right = max($right, $height[$j]);
        }

        $res += min($left, $right) - $height[$i];
    }
    return $res;

}

你應該已經發現了,上面的執行時間是O(n*n)。每一個位置我們都遍歷查詢了左右兩邊,僅僅是為了找最大值,我們為什麼不把每個位置左右兩邊最大值一次存起來?

    /**
 * @param Integer[] $height
 * @return Integer
 */
function trap($height)
{
    $res = 0;
    $size = count($height);
    $left[0] = $height[0];
    for ($i = 1; $i < $size; $i++) {
        $left[$i] = max($left[$i - 1], $height[$i]);
    }
    $right[$size - 1] = $height[$size - 1];
    for ($i = $size - 2; $i >= 0; $i--) {
        $right[$i] = max($right[$i + 1], $height[$i]);
    }

    for ($i = 1; $i < $size - 1; $i++) {
        $res += min($left[$i], $right[$i]) - $height[$i];
    }
    return $res;

}

其實上面的解題思路就是一個動態規劃的過程。動態規劃最重要的兩步:1是狀態的定義,即上面的這兩個定義:

$left[0] = $height[0];
$right[$size - 1] = $height[$size - 1];

第二步就是狀態轉移方程,即上面的

$left[$i] = max($left[$i - 1], $height[$i]);
 $right[$i] = max($right[$i + 1], $height[$i]);

其實動態規劃就像是開啟了上帝的視角,每次都能獲取到全域性的情況。經常用來解最優,最近,最少這類題目。你再進一步分析,好像動態規劃的思想就是一個空間換時間的方案。第一個解的時間是O(n的平方),空間就一個變數O(1)。再來看第二道解,時間是O(n),空間是O(n)。本質上來說就是空間換時間的方案。最後其實這道題還有其他能解的方案。。。。刷著刷著,樂趣就上來了。

Leetcode-php

本作品採用《CC 協議》,轉載必須註明作者和本文連結

吳親庫裡

相關文章