1. 程式人生 > 其它 >LeetCode 0042 Trapping Rain Water

LeetCode 0042 Trapping Rain Water

原題傳送門

1. 題目描述

2. Solution 1: Brute force

1、思路分析
對於每一個高度i,它所能裝下的水:
左邊最大值 右邊最大值
r[i] = min( max(h[0~i]), max(h[i~n-1]) ) - h[i]
遍歷累加即可。

2、程式碼實現

package Q0099.Q0042TrappingRainWater;

public class Solution1 {
    /*
       For column_i, the rain it can trap:
                    左邊最大值      右邊最大值
         r[i] = min( max(h[0~i]), max(h[i~n-1]) )  - h[i]
       Approach 1: Brute force
       For each column, find max of left and right which takes O(n)
       Time complexity: O(n^2)
       Space complexity: O(1)
      */
    public int trap(int[] height) {
        int ans = 0;
        int size = height.length;
        for (int i = 1; i < size - 1; i++) {
            int maxLeft = 0, maxRight = 0;
            for (int j = i; j >= 0; j--) { // Search the left part for max bar size.
                maxLeft = Math.max(maxLeft, height[j]);
            }
            for (int j = i; j < size; j++) { // Search the right part for max bar size.
                maxRight = Math.max(maxRight, height[j]);
            }
            ans += Math.min(maxLeft, maxRight) - height[i];  // 按當前列逐步增量
        }
        return ans;
    }
}

3、複雜度分析
時間複雜度: O(n^2)
空間複雜度: O(1)

3. Solution 2

1、思路分析
DP,對於每個高度i,先暫存左邊最大高度和右邊最大高度,用於後續計算。
l[i] = i == 0 ? max(h[0: i+1]) = h[i] : max(l[i-1], h[i])
r[i] = i == (n-1) ? max(h[i:n]) = h[i] : max(l[i+1], h[i])
ans = sum(min(l[i], r[i]) - h[i])

2、程式碼實現

package Q0099.Q0042TrappingRainWater;

public class Solution2 {
    /*
      Approach 2: DP
      l[i] = i == 0  ? max(h[0: i+1]) = h[i] : max(l[i-1], h[i])
      r[i] = i == (n-1) ? max(h[i:n]) = h[i] : max(l[i+1], h[i])
      ans = sum(min(l[i], r[i]) - h[i])
      Time complexity: O(n)
      Space complexity: O(n)
     */
    public int trap(int[] height) {
        if (height == null || height.length == 0) return 0;
        int ans = 0;
        int size = height.length;
        int[] left_max = new int[size];
        int[] right_max = new int[size];
        left_max[0] = height[0];
        for (int i = 1; i < size; i++) {
            left_max[i] = Math.max(height[i], left_max[i - 1]);
        }
        right_max[size - 1] = height[size - 1];
        for (int i = size - 2; i >= 0; i--) {
            right_max[i] = Math.max(height[i], right_max[i + 1]);
        }
        for (int i = 1; i < size - 1; i++) {
            ans += Math.min(left_max[i], right_max[i]) - height[i];
        }
        return ans;
    }
}

3、複雜度分析
時間複雜度: O(n)
空間複雜度: O(n)

4. Solution 3

1、思路分析
雙指標(Two Pointers),可以使用兩個變數left_max,right_max來儲存當前的左邊最大值和右邊最大值。用變數left、right來定位兩邊,若left_max < right_max,能裝下的最大雨水由left_max決定,故移動left。(短板原理)。

2、程式碼實現

package Q0099.Q0042TrappingRainWater;

public class Solution3 {
    /**
     * Approach 3: Two Pointers
     * We can use two variables to track the max_l and max_r so far.
     *
     * Use l, r to track two sides, move l, r based on whether max_l < max_r. if max_l < max_r,
     * answer depends on max_l, so we move l. 短板原理
     * time complexity: O(n)
     * space complexity: O(1)
     * @param height
     * @return
     */
    public int trap(int[] height) {
        int left = 0, right = height.length - 1;
        int ans = 0;
        int left_max = 0, right_max = 0;
        while (left < right) {
            if (height[left] < height[right]) {
                if (height[left] >= left_max) {
                    left_max = height[left];
                } else {
                    ans += (left_max - height[left]);
                }
                ++left;
            } else {
                if (height[right] >= right_max) {
                    right_max = height[right];
                } else {
                    ans += (right_max - height[right]);
                }
                --right;
            }
        }
        return ans;
    }
}

3、複雜度分析
時間複雜度: O(n)
空間複雜度: O(1)

5. Solution 4

1、思路分析
維護一個單調棧,單調棧儲存的是下標,滿足從棧底到棧頂的下標對應的陣列height中的元素遞減。從左到
右遍歷陣列,遍歷到下標i時,如果棧內至少有兩個元素,記棧頂元素為top,top的下面一個元素是left,則一定有height[left] >= height[top]。如果height[i] > height[top],則得到一個可以接雨水的區域,該區域的寬度為i-left-1,高度是min{height[left], height[i]} - height[top],根據寬度和高度即可計算該區域能接到的雨水量。
為了得到left,需要將top出棧。在對top計算能接的雨水量之後,left變成新的top,重複上述操作,直到棧變為空,或者棧頂下標對應的height中的元素大於或等於height[i]。

2、程式碼實現

package Q0099.Q0042TrappingRainWater;

import java.util.Deque;
import java.util.LinkedList;

public class Solution4 {
    /*
      方法4: 單調棧
     */
    public int trap(int[] height) {
        int ans = 0, current = 0;
        Deque<Integer> stack = new LinkedList<>();
        while (current < height.length) {
            while (!stack.isEmpty() && height[current] > height[stack.peek()]) {
                int top = stack.pop();
                if (stack.isEmpty()) break;
                int distance = current - stack.peek() - 1;
                int boundedHeight = Math.min(height[current], height[stack.peek()]) - height[top];
                ans += distance * boundedHeight;
            }
            stack.push(current++);
        }
        return ans;
    }
}

3、複雜度分析
時間複雜度: O(n)
空間複雜度: O(n)

6. Solution 5

1、思路分析
Keep track of the already safe level and the total water so far. In each step, process and discard the lower one of the leftmost or rightmost elevation.
2、程式碼實現

package Q0099.Q0042TrappingRainWater;

public class Solution5 {
    /*
      Keep track of the already safe level and the total water so far.
      In each step, process and discard the lower one of the leftmost
      or rightmost elevation.
      time complexity: O(n)
      space complexity: O(1)
     */
    public int trap(int[] height) {
        int l = 0, r = height.length - 1, level = 0, water = 0;
        while (l < r) {
            int lower = height[height[l] < height[r] ? l++ : r--];
            level = Math.max(level, lower);
            water += level - lower;
        }
        return water;
    }
}

3、複雜度分析
時間複雜度: O(n)
空間複雜度: O(1)