【LeetCode】42.接雨水

題目鏈接

42. 接雨水

題目描述

解題思路

暴力法(按列求取雨水值)

因爲首尾元素不可能存在雨水,所以可以不用考慮首尾元素。

對於剩餘的每個元素,分別計算從該元素開始,從左和從右開始開始的最大值,然後當前元素對應的能夠接的雨水值 = Math.min(maxLeft,maxRight) - height[i];

時間複雜度:O(n2)

空間複雜度:O(1)

動態規劃

在暴力法中,我們每次都要計算當前座標對應的左邊最大值maxLeft以及右邊最大值maxRight,所以直接導致時間複雜度爲O(n2),然而這些值都是固定的,所以我們可以提前利用兩個數組maxleft[]以及maxRight[]記錄每個下標對應的左邊最大值和右邊最大值。

時間複雜度:O(n)

空間複雜度:O(n)

單調棧

單調遞減棧,棧中存放的是索引值,因爲通過索引值也可以得到height數組中的元素值。

如果當前索引對應的height數組值 <= 前一個索引對應的height數組值,那麼接不雨水。

如果當前索引對應的height數組值 > 前一個索引對應的height數組值,那麼纔有可能接到雨水(注意是有可能,而不是一定,只有同時滿足單調棧不爲空的時候才能接到雨水)

參考下圖就一目瞭然,利用單調棧也可以理解爲是按行計算雨水值

如果當前下標對應的height數組值小於棧頂元素則入棧。

如果當前下標對應的height數組值大於棧頂元素且當前stack不爲空,則說明此時這種情況存在雨水值,雨水值的計算方式如下:

  • 首先記錄value = 彈棧元素對應的height數組值
  • 其次記錄Math.min(新的棧頂元素對應的height數組值,以及當前索引對應的height數組值),然後減去value值,則爲水坑對應的高度。
  • 水坑的寬度 = 當前索引 - 新的棧頂元素。

參考資料

AC代碼

暴力法

class Solution {
    //按照每列的雨水數目計算結果
    public int trap(int[] height) {
        int ans = 0;
        //因爲開頭結尾不會有雨水,所以可以不用考慮
        for(int i = 1; i < height.length - 1; i++){
            int maxLeft = height[i];
            int maxRight = height[i];
            for(int j = i - 1; j >= 0; j--){
                if(height[j] > maxLeft){
                    maxLeft = height[j];
                }
            }
            for(int j = i + 1; j < height.length; j++){
                if(height[j] > maxRight){
                    maxRight = height[j];
                }
            }
            ans += Math.min(maxLeft,maxRight) - height[i];
        }
        return ans;
    }
}

動態規劃

class Solution {
    public int trap(int[] height) {
        if(height.length == 0) return 0;
        int maxLeft[] = new int[height.length];
        int maxRight[] = new int[height.length];
        int ans = 0;
        maxLeft[0] = 0;
        for(int i = 1; i < height.length; i++){
            maxLeft[i] = Math.max(height[i - 1],maxLeft[i-1]);
        }
        maxRight[height.length-1] = 0;
        for(int i = height.length - 2; i >= 0; i--){
            maxRight[i] = Math.max(height[i+1],maxRight[i+1]);
        }
        for(int i = 1; i < height.length; i++){
            int h = Math.min(maxLeft[i],maxRight[i]);
            if(h > height[i]){
                ans += h - height[i];
            }
        }
        return ans;
    }
}

//改進版動態規劃
class Solution {
    public int trap(int[] height) {
        if(height.length == 0) return 0;
        int maxRight[] = new int[height.length];
        int ans = 0;
        int maxLeft = 0;
        maxRight[height.length-1] = 0;
        for(int i = height.length - 2; i >= 0; i--){
            maxRight[i] = Math.max(height[i+1], maxRight[i+1]);
        }
        for(int i = 1; i < height.length; i++){
            maxLeft = Math.max(maxLeft,height[i - 1]);
            int h = Math.min(maxLeft,maxRight[i]);
            if(h > height[i]){
                ans += h - height[i];
            }
        }
        return ans;
    }
}

//改進版,雙指針法
public int trap(int[] height) {
    int sum = 0;
    int max_left = 0;
    int max_right = 0;
    int left = 1;
    int right = height.length - 2; // 加右指針進去
    for (int i = 1; i < height.length - 1; i++) {
        //從左到右更
        if (height[left - 1] < height[right + 1]) {
            max_left = Math.max(max_left, height[left - 1]);
            int min = max_left;
            if (min > height[left]) {
                sum = sum + (min - height[left]);
            }
            left++;
        //從右到左更
        } else {
            max_right = Math.max(max_right, height[right + 1]);
            int min = max_right;
            if (min > height[right]) {
                sum = sum + (min - height[right]);
            }
            right--;
        }
    }
    return sum;
}

作者:windliang
鏈接:https://leetcode-cn.com/problems/trapping-rain-water/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-8/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

單調棧

class Solution {
    public int trap(int[] height) {
        Stack<Integer> st = new Stack<>();
        int ans = 0;
        for(int i = 0; i < height.length; i++){
            while(!st.isEmpty() && height[i] > height[st.peek()]){
                int index = st.pop();
                int value = height[index];
                if(st.isEmpty() == false) ans += (Math.min(height[st.peek()],height[i]) - value) * (i-st.peek()-1);
            }
            st.push(i);
        }
        return ans;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章