1. 程式人生 > >42.trapping-rain-water

42.trapping-rain-water

      以前在聽演算法課的時候,有一個人說過這樣一句話,凡是那道題沒有思路的9成要用動態規劃,當然可能說的有點絕對,但是不無道理,就是說,一般的題目我們遇到後能立即想到思路,哪怕是那種很麻煩的,但是動態規劃往往是麻煩的也不一定能想出來。而動態規劃的難度也確實比較大,其靈活性很高,他不同於字串,陣列,排序這種的某一類問題,他是一種思想,滲透到各種各樣的問題的當中,而leetcode有關動歸的問題還不在少數,比較全面。

        題目的大致意思是,給定一個一維陣列,每個數字表示對應位置的地基高度,類似於地面的凹凸不平狀態,不同的是,這個題目中要求的維度是二維,假設在下雨的時候,凹進去的地面會存入一定量的雨水,存入雨水的多少取決於左右兩邊最大高度中最小的那一個與該位置的高度差,類似於木桶理論,比如有一個地面是 4 3 5,那麼它的最大積水量是 min(5, 4)-3 = 1。

        基於以上的理解,我們就可以使用動態規劃的思路,將每一個位置點左側的最大高度存起來,然後將每個位置點右側的最大高度存起來,這樣,該位置的最大存水量為min(maxleft[i], maxright[i])-height[i] 得到,最後將所有位置相加即可,為了提高空間複雜度方面的效能,我們只需要將所有位置對應的左側最大高度存在一個數組中,然後每算出一個右側最大高度,就將該位置對應的存水量算出來,接著進行下一位的計算。

根據以上的思路,下面是AC程式碼:

class Solution {
public:
    int trap(vector<int>& height) {
        vector<int> dp(height.size(), 0);
        int maxleft = 0;
        for (int i=0; i<height.size(); ++i) {
            dp[i] = maxleft;
            maxleft = max(height[i], maxleft);
        }
        int maxright = 0, res = 0;
        for (int i=height.size()-1; i>=0; --i) {
            dp[i] = min(dp[i], maxright);
            maxright = max(maxright, height[i]);
            if (dp[i]-height[i] > 0) {
                res += (dp[i]-height[i]);
            }
        }
        return res;
    }
};