LeetCode-42 Receiving rainwater, more solutions, clear ideas

Question details

Given n non-negative integers representing the height map of each column with a width of 1, calculate how much rain can be received by the columns arranged in this way after it rains.

Example 1:
Insert picture description here

Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6
Explanation: The above is composed of the array [0,1,0,2,1,0 ,1,3,2,1,2,1] represents the height map. In this case, 6 units of rainwater can be received (the blue part represents rainwater).
Example 2:

Input: height = [4,2,0,3,2,5]
Output: 9

Three solutions

The first solution is my own idea. The more violent method at the beginning is actually a bit similar to the stack.
The area is calculated in different levels.

	public int trap(int[] height) {
    
    
        //思路有了,这题和11题一点都不一样,需要考虑的东西实际很复杂
        //也是双指针,但需要记录下当前的高度,每次高度来计算一下面积
        //当后面的高度大于前面的,只需要记录下当前由于高度增加而新增的面积,从而防止重复计算
        int l=0, r=height.length-1, res=0;
        int cur_hi = 0;//当前高度
        while(l<r){
    
    
            //只要当高度更新了,才会计算面积
            if(Math.min(height[l],height[r])>cur_hi){
    
    
                res += calcArea(height,cur_hi,l,r);
                cur_hi = Math.min(height[l],height[r]);
            }
            //移动l与r
            if(height[l]<=height[r]){
    
    
                l++;
            }
            else{
    
    
                r--;
            }
        }
        return res;
    }

    /**
    计算中间能接多少雨水
    **/
    private int calcArea(int[] height,int cur_hi, int l, int r){
    
    
        if(r-l<2){
    
    
            return 0;
        }
        int real_height = Math.min(height[l],height[r]);
        int area = 0;
        for(int i=l+1; i<r; i++){
    
    
            //每个节点的高度如果低于cur_hi,就按cur_hi来看,如果高于cur_hi,就按自己看
            int cur = height[i]>cur_hi ? height[i] : cur_hi;
            //每次按照边界和高度确定当前的接水高度
            area += Math.max(0,real_height-cur);
        }
        return area;
}

This solution makes full use of pruning, but because the complexity is O(n2), it is a bit slow. 4ms

Then there is the solution of double pointer O(n).

public int trap(int[] height) {
    
    
    // 来进行双指针O(n)的练习
    // 这里的逻辑是双指针进行走,每次记录左右已遍历最大值
    // 如果移动到当前值小于自己这部分最大值,则意味着两件事。
    // 第一件事便是,因为当前值移动,所以另一部分一定大于当前值。因为双指针逻辑是小的移动
    // 第二件事便是,因为当前值小自己这部分最大值,所以在自己位置一定能装下 这部分最大值-自己值的水
    // 这里这部分最大值<另一边显然,不然,另一边就会移动
    // 所以秉承着这样的想法,整个双指针法就得到了证明,下面来实现代码逻辑
    int l=0, r=height.length-1, lmax=0, rmax=0, res=0;
    while(l<r){
    
    
        if(height[l]<=height[r]){
    
    
            if(height[l]>lmax){
    
    
                lmax = height[l];
            }
            else{
    
    
                res += lmax-height[l];
            }
            l++;
        }
        else{
    
    
            if(height[r]>rmax){
    
    
                rmax = height[r];
            }
            else{
    
    
                res += rmax-height[r];
            }
            r--;
        }
    }
    return res;
}

The specific ideas and proof of understanding are written in the notes.

The next one is the stack.

public int trap(int[] height) {
    
    
    //果然就很快
    //下面尝试用栈的方式找
    //栈的思路在于从左开始往右走
    //如果栈空,入栈
    //如果小于栈顶,入栈(其实就是小于前一个数)
    //如果大于,则一直与栈里的元素比较,计算相互匹配上的area,直到当前柱子比栈顶柱子低(其实就是与左边柱子计算中间能放多少雨水)
    
    int ans = 0, current = 0;
    Deque<Integer> stack = new LinkedList<Integer>();
    while (current < height.length) {
    
    
        while (!stack.isEmpty() && height[current] > height[stack.peek()]) {
    
    
            //这里只要栈不为空,cur是不变的,因为右边高的柱子要一直和左边低的每个柱子进行匹配
            int top = stack.pop();
            if (stack.isEmpty())
                break;
            int distance = current - stack.peek() - 1;
            int bounded_height = Math.min(height[current], height[stack.peek()]) - height[top];
            ans += distance * bounded_height;
        }
        stack.push(current++);
    }
    return ans;
}

Guess you like

Origin blog.csdn.net/qq_34687559/article/details/110083942