Leetcode42.接雨水——双指针法

文章目录

引入

本题是这样的:

42.接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
在这里插入图片描述

题目给出的图片一眼就能了然题目要问的是什么。

很明显,某一列能装多少水,取决于该列左侧和右侧的高度的最小值。
最无脑的做法就是,对每一列求其左右的最大值,也就是用额外的两个O(N)大小的数组空间来存储每一列的最大值和最小值。
该方法时间复杂度也是O(N),不过是需要2-3次遍历数组(求最大值一次,最小值一次,然后求盛水高度一次,后面两次可以合并)。

不过,我希望能够一次遍历完成计算,并且不需要使用额外的数组空间,一开始我是这样写的:

class Solution {
    public int trap(int[] height) {
        int output=0;
        int left=height[0];
        for(int i=1;i<height.length;i++){
            if(height[i]<left) output+=(left-height[i]);
            else{
                left=height[i];
            }
        }
        return output;
    }
}

这样写,值考虑左侧的值,并没有考虑右侧值是否比左侧值更小,当然是错的。不过提供了一种思路,是否能够用相似的方法一次遍历并且不实用额外的数组空间呢?

双指针法

由之前的解法,我们看到,只考虑了一侧的值(左侧),而忽略了另一侧的值,这样是不可取的。因为水位高度取决于最低的那块板子。

所以,我们想到,是否能用双指针,分别来指向左右两侧,然后比较左侧目前的max_height大还是右侧目前的max_height大。其具体步骤是这样的:

  1. left=0, right=length-1;//两个指针从左右分别开始。
  2. left_max_height=height[left],right_max_height=height[right];记录下左右两边的目前指针指向的最高的高度。
  3. 当left<right的时候,判断左边的最大高度大还是右边的最大高度大。如果是右边的最大高度更大,那么左边无论如何都会装上水,因为它是矮的那一块。
  4. 不妨假设是左边的最大高度小一点,判断目前的height和left_max_height的关系。如果目前的高度比left_max_height高度更高,再次进入步骤3。否则计算盛水量:left_max_height-height。指针left++,重复步骤4直到不满足left<right。
{
    int left = 0, right = height.length - 1;
    int ans = 0;
    int left_max_height = 0, right_max_height = 0;
    while (left < right) {
        if (height[left] < height[right]) {
            if(height[left] >= left_max_height) {
				left_max_height = height[left];
			}else{
				ans += (left_max_height - height[left]);
			}
            ++left;
        }
        else {
        	if(height[right] >= right_max){
        		right_max_height = height[right];
        	}else{
        		ans += (right_max_height - height[right]);
        	} 
            --right;
        }
    }
    return ans;
}
发布了364 篇原创文章 · 获赞 324 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/No_Game_No_Life_/article/details/103858151