LearningRecord icon indicating copy to clipboard operation
LearningRecord copied to clipboard

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水

Open Rashomon511 opened this issue 5 years ago • 0 comments

思路: 方法一:

  • 首先找出整个区域最大的数值,记录位置
  • 以位置为中心向左找最大的数值, 计算两个位置的容量,并更新最大值的地址,直到循环结束
  • 以位置为中心向右找最大的数值,计算两个位置的容量,并更新最大值的地址,直到循环结束
        const trapRainWater = (heights) => {
            if (heights.length <= 2) return 0;
            let max = -1, maxInd = 0;
            let i = 0;
            for (; i < heights.length; ++i) {
                if (heights[i] > max) {
                    max = heights[i];
                    maxInd = i;
                }
            }
            let area = 0, root = heights[0];
            for (i = 0; i < maxInd; ++i) {
                if (root < heights[i]) root = heights[i];
                else area += (root - heights[i]);
            }
            for (i = heights.length - 1, root = heights[heights.length - 1]; i > maxInd; --i) {
                if (root < heights[i]) root = heights[i];
                else area += (root - heights[i]);
            }
            console.log(area)
            return area;
        }

方法二: 首先从左遍历一遍,找到已左边为基准的高度 再从右边遍历一遍找到以右边为基准的高度, 要能够接住水,就要求左右两边,最小的一边的高度应该比中间的都要大,能接住的水的面积就是这些差值。

        const trapRainWater2 = (A) => {
            if(A == null || A.length < 3)
            return 0;
        
        let localMax = A[0];
        let left = Array.from(new Array(A.length));
        let right = Array.from(new Array(A.length));
        
        for(let i=0;i<A.length;i++) {
            if(A[i] <= localMax)
                left[i] = localMax;
            else {
                localMax = A[i];
                left[i] = localMax;
            }
        }
        
        localMax = A[A.length-1];
        for(let i=A.length-1;i>-1;i--) {
            if(A[i] <= localMax)
                right[i] = localMax;
            else {
                localMax = A[i];
                right[i] = localMax;
            }
        }
        
        let area = 0;
        for(let i=0;i<A.length;i++) {
            area += Math.min(left[i], right[i]) - A[i];
        }
        console.log(area)
        return area;
        }

方法三 左右两个指针,一头一尾开始遍历,首先找到自己这一边的局部最高点,只要比最高点小就可以装水

        const trapRainWater = (A) => {
            if (A == null || A.length < 3)
                return 0;

            //两根指针一头一尾向中间进发
            let left = 0;
            let right = A.length - 1;
            //两个变量存储左右两边的局部最大高度
            let leftMax = 0;
            let rightMax = 0;

            let area = 0;

            while (left <= right) {
                leftMax = Math.max(leftMax, A[left]);
                rightMax = Math.max(rightMax, A[right]);

                //小的那边可以存水
                if (leftMax <= rightMax) {
                    if (leftMax > A[left]) {
                        area += leftMax - A[left];
                    }

                    left++;
                }
                else {
                    if (rightMax > A[right]) {
                        area += rightMax - A[right];
                    }
                    right--;
                }
            }
            return area;
        }

Rashomon511 avatar May 27 '19 12:05 Rashomon511