Monday, April 17, 2017

42. Trapping Rain Water

三刷 07/2022
Version #4 Two Pointers
Time O(N)
Space O(1)
Runtime: 2 ms, faster than 56.76% of Java online submissions for Trapping Rain Water.
Memory Usage: 49 MB, less than 33.16% of Java online submissions for Trapping Rain Water.

class Solution {
    public int trap(int[] height) {
        int left = 0, right = height.length - 1;
        int leftMax = 0, rightMax = 0;
        int sum = 0;
        //  l           r
        // [2, 1, 3, 1, 4]
        while (left <= right) {
            if (height[left] < height[right]) {
                if (height[left] > leftMax) {
                    leftMax = height[left];
                } else {
                    sum += leftMax - height[left];
                }
                left++;
            } else {
                if (height[right] > rightMax) {
                    rightMax = height[right];
                } else {
                    sum += rightMax - height[right];
                }
                right--;
            }
        }
        return sum;
    }
}



Version #3 Two Passes Iteration
Time O(N)
Space O(N)
Runtime: 2 ms, faster than 56.76% of Java online submissions for Trapping Rain Water.
Memory Usage: 48.9 MB, less than 33.16% of Java online submissions for Trapping Rain Water.
class Solution {
    public int trap(int[] height) {
        int[] right = new int[height.length];
        int r = 0;
        for (int i = height.length - 1; i >= 0; i--) {
            right[i] = r;
            if (height[i] > r) {
                r = height[i];
            }
        }
        int l = 0;
        int sum = 0;
        for (int i = 0; i < height.length; i++) {
            if (Math.min(l, right[i]) > height[i]) {
                sum += Math.min(l, right[i]) - height[i];
            }
            if (height[i] > l) {
                l = height[i];
            }
        }
        return sum;
    }
}


Version #2 Stack - better

Time O(N)
Space O(N)
Runtime: 16 ms, faster than 10.10% of Java online submissions for Trapping Rain Water.
Memory Usage: 49.6 MB, less than 10.71% of Java online submissions for Trapping Rain Water.

class Solution {
    public int trap(int[] height) {
        Stack<Integer> stack = new Stack<>();
        int sum = 0;
        for (int i = 0; i < height.length; i++) {
            while (!stack.isEmpty() && height[stack.peek()] < height[i]) {
                int bottom = height[stack.pop()];
                if (stack.isEmpty()) {
                    break;
                }
                sum += (Math.min(height[i], height[stack.peek()]) - bottom) * (i - stack.peek() - 1);
            }
            stack.push(i);
        }
        return sum;
    }
}



Version #1 Stack - naiive
100%自己写的方法,维护一个bottom表示之前fill到的height,每次pop出前一个比自己小的height然后从bottom fill到height
这个方法一开始写了bug就是当当前点低于前一个element的时候也是可以fill的,譬如
4, 2, 0, 3, 2, 5 在走到3的时候如果只pop到2就是不对的,要一直看到4但是不把4pop出来
看到之前的写法是看stack里面的两个值,一个作为bottom,一个作为left

Time O(N)
Space O(N)
Runtime: 26 ms, faster than 5.92% of Java online submissions for Trapping Rain Water.
Memory Usage: 49.1 MB, less than 24.21% of Java online submissions for Trapping Rain Water.
class Solution {
    public int trap(int[] height) {
        int sum = 0;
        // Monotonic decreasing stack of the indices
        Stack<Integer> stack = new Stack<>();
        int bottom = 0;
        for (int i = 0; i < height.length; i++) {
            if (stack.isEmpty() || height[i] < height[stack.peek()]) {
                stack.push(i);
                continue;
            }
            // current height is larger than the element in the stack
            while (!stack.isEmpty() && height[stack.peek()] <= height[i]) {
                int left = stack.pop();
                // System.out.printf("=>left=%d,height[left]=%d, bottom=%d, i=%d\n",left, height[left], bottom, i);
                sum += (height[left] - bottom) * (i - left - 1);
                bottom = height[left];
            }
            if (!stack.isEmpty() && height[stack.peek()] > height[i]) {
                int left = stack.peek();
                // System.out.printf("left=%d,height[left]=%d, bottom=%d, i=%d\n",left, height[left], bottom, i);
                sum += (height[i] - bottom) * (i - left - 1);
                bottom = height[i];
            }
            stack.push(i);
            if (stack.isEmpty()) {
                bottom = 0;
            }
        }
        return sum;
    }
}

Version #1 Stack

二刷
Keep track of the left height of each base
Fill the water layer by layer
Time O(n)
Space O(n)

 22.32 %
class Solution {
    public int trap(int[] height) {
        // a hight of a col is defined by min(leftMax, rightMax)
        // keep a descreasing stack of index
        Stack<Integer> stack = new Stack<>();
        // stack of indexes
        // if coming bar is higher than height[stack.peek()], h = Math.min(left, right) - stack.peek()
        // width = right - left - 1
        // stack 1 3
        //  0 1 2 3 4 5 6 7 8 9 10 11
        //    i
        // [0,1,0,2,1,0,1,3,2,1,2,1]
        int sum = 0;
        for (int i = 0; i < height.length; i++) {
            int rHeight = height[i]; // 2
            while (!stack.isEmpty() && height[stack.peek()] < rHeight) {
                int base = height[stack.pop()];
                if (!stack.isEmpty()) {
                    int lHeight = height[stack.peek()];
                    sum += (Math.min(lHeight, rHeight) - base) * (i - stack.peek() - 1);
                }
            }
            stack.push(i);
        }
        return sum;
    }
}


一刷



public class Solution {
    public int trap(int[] height) {
        if (height == null || height.length == 0) return 0;
        int leftMax = 0;
        //stack of indicies of bars need to be calculated
        Stack<Integer> stack = new Stack<>();
        int sum = 0;
        int index = 0;
        while (index < height.length) {
            if (stack.isEmpty() || height[index] < height[stack.peek()]) {
                stack.push(index);
                //System.out.println("stack" + stack.peek());
                index++;
            } else {
                int bottom = height[stack.pop()];
                //System.out.println("bottom" + bottom);
           
                if (!stack.isEmpty()) {
                    int left = height[stack.peek()];
                    sum += (Math.min(left, height[index]) - bottom) * (index - stack.peek() - 1);
                    //System.out.println(Math.min(left, height[index]));
                }
            }
        }
        return sum;
    }
}


Version #2 Two pointers

public class Solution {
    /**
     * @param heights: an array of integers
     * @return: a integer
     */
    public int trapRainWater(int[] heights) {
        // write your code here
        if (heights == null || heights.length < 3) return 0;
        int sum = 0;
        int left = 0, right = heights.length - 1;
        int leftMax = heights[left];
        int rightMax = heights[right];
        while (left + 1 < right) {
            //start to fill from the left side
            if (leftMax < rightMax) {
                left++;
                if (heights[left] >= leftMax) leftMax = heights[left];
                else {
                    sum += leftMax - heights[left];
                }
            //start to fill from the right side
            } else {
                right--;
                if (heights[right] >= rightMax) rightMax = heights[right];
                else {
                    sum += rightMax - heights[right];
                }
            }
        }
        return sum;
    }
}


Version #3 1Pointer 2Pass
Scan from left to right to get the maxLeft array
Then scan back from right to left to get the maxRight array and calculate the volume at the same time

Time  O(n) 2pass
Space O(n)
38.90 %

public class Solution {
    public int trap(int[] height) {
        if (height == null || height.length == 0) return 0;
        int[] left = new int[height.length];
        int maxLeft = 0;
        for (int i = 0; i < height.length; i++) {
            left[i] = maxLeft;
            maxLeft = Math.max(maxLeft, height[i]);
        }
        int sum = 0;
        int maxRight = 0;
        for (int j = height.length - 1; j >= 0; j--) {
            //min(maxLeft, maxRight)
            int volume = Math.min(left[j], maxRight) - height[j];
            if (volume > 0) sum += volume;
            maxRight = Math.max(height[j], maxRight);
        }
        return sum;
    }
}

No comments:

Post a Comment