1. 程式人生 > 遊戲攻略 >《夏洛克福爾摩斯第一章》圖文攻略 全解謎圖文流程攻略

《夏洛克福爾摩斯第一章》圖文攻略 全解謎圖文流程攻略

給定 n 個非負整數表示每個寬度為 1 的柱子的高度圖,計算按此排列的柱子,下雨之後能接多少雨水。

示例 1:

  • 輸入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
  • 輸出:6
  • 解釋:上面是由陣列 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度圖,在這種情況下,可以接 6 個單位的雨水(藍色部分表示雨水)

雙指標解法

按照列來計算的話,寬度一定是1了,我們再把每一列的雨水的高度求出來就可以了。

可以看出每一列雨水的高度,取決於,該列 左側最高的柱子和右側最高的柱子中最矮的那個柱子的高度

即: min(lHeight, rHeight) - height

class Solution {
    public int trap(int[] height) {
        return process(height);
    }

    private int process(int[] height){
        //按列計算
        //i:left Max. rightMax. h= min(leftMax,rightMax)-heigt[i]>0 sum+=h
        if(height.length<=2){
            return 0;
        }
        int sum=0;
        for(int i=1;i<height.length-1;i++){
            int leftMax=getRangeMax(height,0,i);
            int rightMax=getRangeMax(height,i,height.length-1);
            int h=Math.min(leftMax,rightMax)-height[i];
            if(h>0){
                sum+=h;
            }
            
        }
        return sum;
    }

    private int getRangeMax(int[] height,int L,int R){
        int max=0;
        for(int i=L;i<=R;i++){
            max=Math.max(max,height[i]);
        }
        return max;
    }
}

  

動態規劃解法

為了得到兩邊的最高高度,使用了雙指標來遍歷,每到一個柱子都向兩邊遍歷一遍,這其實是有重複計算的。

我們把每一個位置的左邊最高高度記錄在一個數組上(maxLeft),右邊最高高度記錄在一個數組上(maxRight)。這樣就避免了重複計算,這就用到了動態規劃。

當前位置,左邊的最高高度是前一個位置的左邊最高高度和本高度的最大值。

即從左向右遍歷:maxLeft[i] = max(height[i], maxLeft[i - 1]);

從右向左遍歷:maxRight[i] = max(height[i], maxRight[i + 1]);

這樣就找到遞推公式。

class Solution {
    public int trap(int[] height) {
        return process(height);
    }

    private int process(int[] height){
       //leftMax[i] 0....i 求得每個位置左邊的最大值 leftMax[i]=Math.max(dp[i-1],height[i])
       //rightMax[i] i....R 求得每個位置右邊的最大值 rightMax[i]=Maht.max(dp[i+1],heigth[i])
       //遍歷1....i-1. Math.min(leftMax(i),rightMax(i))-heigt[i]
       //h >0 sum+=h
       int n=height.length;
       if(n<=2){
           return 0;
       }
       int[] leftMax=new int[n];
       leftMax[0]=height[0];
       for(int i=1;i<n;i++){
           leftMax[i]=Math.max(leftMax[i-1],height[i]);
       }

       int[] rightMax=new int[n];
       rightMax[n-1]=height[n-1];
       for(int i=n-2;i>=0;i--){
           rightMax[i]=Math.max(rightMax[i+1],height[i]);
       }

       int sum=0;
       for(int i=1;i<n-1;i++){
           int h=Math.min(leftMax[i],rightMax[i])-height[i];
           if(h>0) sum+=h;
       }

       return sum;
       
    }


}

  

單調棧解法