leetcode-接雨水

 题目来自LeetCode,链接:接雨水

 首先说一个我自己琢磨出来的解法,首先观察会有水的区间。假设把这些整数看作是山地的高度,整个数组就构成了一个高低起伏的山脉,这里面有峰有谷也有坡,那么水会存在哪呢,很容易想到,就只能存在于峰与峰之间。所以我们需要做的第一项工作就是找到各个峰的位置,所谓的峰,这里的定义是不低于左边且比右边高(所以峰就是一个非减序列的最后一个数)。找到所有这些峰之后,还需要去掉一些会被水淹没的峰(其左右的峰不比它低就会发生这种情况)。当我们把这种会被淹没的峰都去掉之后,剩下的就是承担了分隔峰作用的了,也就是其必定是有水区间的一个端点,据此计算各个有水区间的总水量即可。代码较长,就不贴了,放在了Github

 提交结果如下:


 接下来说一下在leetcode评论区看到的其他做法,首先需要知道,对于每个位置(高度为height_current),其装水量取决于其左边的最高高度leftmax和右边的最高高度rightmax: m i n ( l e f t m a x , r i g h t m a x ) h e i g h t _ c u r r e n t min(leftmax, rightmax) - height\_current 。所以可以用两遍遍历,获得每个位置上的左边和右边最高高度,最后再遍历一遍累加各个位置的装水量即可得到结果。时间复杂度为 O ( n ) O(n) ,空间复杂度为 O ( n ) O(n)

 JAVA版代码如下:

class Solution {

    public int trap(int[] height) {
        int N = height.length;
        if (N <= 2) {
            return 0;
        }
        int[] left_max = new int[N];
        int[] right_max = new int[N];

        left_max[0] = height[0];
        for (int i = 1; i < N; ++i) {
            left_max[i] = Math.max(left_max[i - 1], height[i]);
        }
        right_max[N - 1] = height[N - 1];
        for (int i = N - 2; i >= 0; --i) {
            right_max[i] = Math.max(right_max[i + 1], height[i]);
        }

        int result = 0;
        for (int i = 0; i < N; ++i) {
            result += Math.min(left_max[i], right_max[i]) - height[i];
        }

        return result;
    }
}

 提交结果如下:


 要进一步优化的话也只能从遍历次数入手,前面需要两次遍历分别得到leftmax和rightmax,进一步通过观察可以发现对于一个位置上的装水量,其实只跟其左边最高高度与右边最高高度两者的较低者有关,所以可以利用两个指针,左指针初始化指向最左,右指针初始化指向最右,假设现在右指针指向的高度比左指针的高,说明从左边开始,其装水量必然只取决于左边最高高度(因为在左指针与右指针之间不可能存在一个比左指针高度还低的一个分界峰,否则必然会被淹没,换而言之,可能存在的分解峰必定比左指针的高度还高,所以左指针必然是较低者),所以左指针开始往右边走,随时更新左边最高高度,如果左边最高高度大于右边最高高度了,无非就是将上述过程反过来,将右指针往左移罢了。这么做时间复杂度还是 O ( n ) O(n) ,空间复杂度则降到 O ( 1 ) O(1)

 JAVA版代码如下:

class Solution {

    public int trap(int[] height) {
        int N = height.length;
        if (N <= 2) {
            return 0;
        }
        int left = 0, left_max = height[0];
        int right = N - 1, right_max = height[N - 1];

        int result = 0;
        while (left < right) {
            if (left_max < right_max) {
                result += left_max - height[left];
                left_max = Math.max(left_max, height[++left]);
            }
            else {
                result += right_max - height[right];
                right_max = Math.max(right_max, height[--right]);
            }
        }

        return result;
    }
}

 提交结果如下:


 Python版代码如下:

class Solution:
    def trap(self, height: List[int]) -> int:
        N = len(height)
        if N <= 2:
            return 0
        left, right = 0, N - 1
        left_max, right_max = height[0], height[N - 1]
        result = 0
        while left < right:
            if left_max < right_max:
                result += left_max - height[left]
                left += 1
                left_max = max(left_max, height[left])
            else:
                result+= right_max - height[right]
                right -= 1
                right_max = max(right_max, height[right])
        return result

 提交结果如下:


发布了68 篇原创文章 · 获赞 9 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/JR_Chan/article/details/105317753