leetcode 42. Trapping Rain Water

牛客网第一课的第二题

问题:.给定一个非负数的数组,代表一个容器。例如数组[0,1,0,2,1,0,1,3,2,1,2,1],就是以下图形中黑色的部分。如果用这个容器接水的话,请问可以接多少水?还以这个数组为例, 可以接6格水,就是以下图形中蓝色的部分。 要求:实现时间复杂度O(N),额外空间复杂度O(1)的解法。

比较朴素的想法就是我们把数组中的数当作容器壁,求出各个容器壁之间可以存多少水,就可以得到总量了。实现起来不是很容易。这里提出求每个容器壁上面可以存多少水,再将所有的加在一起,得出结果。按照这个思路我们有了以下几种解法。

解法1:求出数组当前位置左右两边的最大值,选择小的那个减去当前位置的值,这个结果就是当前位置的存水量。这个是我们最直接的想法,遍历时,我们要遍历当前位置的左右,其时间复杂度无疑是O(N*N)的。

解法2:基于解法1,我们可以先将当前位置的左右最大值各保存到一个辅助数组中,遍历时直接在辅助数组中取,时间复杂度是O(N)级别的,空间复杂度亦为O(N)级别,在这里我们可以只开一个辅助数组,保存右边的最大值,我们从左遍历时可以得到当前位置的左边最大值,因为我们是从左到右遍历的。

解法3:这里推荐这个解法,比较巧妙,而且复杂度符合题意。我们从数组两段开始遍历,左指针LMAX保存左边当前最大值,右指针RMAX保存右边当前最大值,T=min(LMAX,RMAX),我们可以确定T个位置左边或右边(LMAX和RMAX中间的位置)的存水量。用T减去该位置的值就是该位置的存水量。虽然我们只找到该位置一边的最大值,就是T,但是我们已经找到这个位置的瓶颈了,因为另一边(LMAX或者RMAX)虽然不是最大值,已经比T大了,所以T就是这个位置的短板。接下来T位置向中间滑动一个位置,并更新当前位置最大值。重复上述操作,知道LMAX和RMAX相遇,算法终止,我们只遍历了一遍,时间复杂度O(N),额外空间复杂度,LMAX和RMAX,O(1)级别。

public class LeetCode42 {
	public int trap(int height[]) {
		if (height == null || height.length < 3) {
			return 0;
		}
		int n = height.length;
		int LMAX = height[0];// 左边最大值
		int RMAX = height[n - 1];// 右边最大值
		int sum = 0;
		int L = 1;
		int R = n - 2;
		while (L <= R) {
			if (LMAX <= RMAX) {
				sum += Math.max(LMAX - height[L], 0);
				LMAX = Math.max(LMAX, height[L++]);
			} else {
				sum += Math.max(RMAX - height[R], 0);
				RMAX = Math.max(RMAX, height[R--]);
			}
		}
		return sum;
	}

//	public static void main(String[] args) {
//		int[] a = { 0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1 };
//		System.out.println(trap(a));
//	}
}
在这里,我们有了一个双 指针的玩法:两个指针产生的结果会决定下一步哪个指针动。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值