leetcode 11. 盛最多水的容器(Java版)

43 篇文章 0 订阅
28 篇文章 0 订阅

题目描述(题目难度,中等)

给定 n n n 个非负整数 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1a2...an,每个数代表坐标中的一个点 ( i , a i ) (i, a_i) (i,ai) 。在坐标内画 n n n 条垂直线,垂直线 i i i 的两个端点分别为 ( i , a i ) (i, a_i) (i,ai) ( i , 0 ) (i, 0) (i,0)。找出其中的两条线,使得它们与 x x x 轴共同构成的容器可以容纳最多的水。

说明: 你不能倾斜容器,且 n n n 的值至少为 2。
示例
图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例:

输入: [1,8,6,2,5,4,8,3,7]
输出: 49

示例代码

时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( 1 ) O(1) O(1)

class Solution {
    //这个题放在 在线测试还可以 放在面试中不太好描述吧
    public int maxArea(int[] height) {
    	int i = 0, j = height.length - 1;
    	int mm = 0;//用于存遍历过程中得到的存水最大值
    	while(true){
    		int m = (j-i)*(height[i] <= height[j]?height[i++]:height[j--]);
    		if(m > mm) mm = m;
    		if(i == j) break;
    	}
        return mm;
    }
}

思路解析

上面是一种双指针算法,指针 i 指向数组的开头,满足条件后只向后移动;指针 j 指向数组的末尾,满足条件后只向前移动。两指针相遇,算法结束。能使用这种算法解的题还有很多,在最后我还会举个例子。
那么指针移动的条件是什么呢?
在本题中指针移动的条件是,如果 a[i] <= a[j],那么指针 i 则向后移动;如果 a[i] > a[j],那么指针 j 则向前移动。
我们可以发现,虽然 i,j 指针合起来能遍历整个数组,但并没有穷举所有的容器情况。 例如,如果 a[i] <= a[j],则 i++,排除了 a[i] 与 a[i+1,…,j-1] 之间的某个数构成最大盛水容器的可能性。 为什么可以这样做呢?下面给出证明:
假设存在 k,k 满足 i+1 <= k <= j-1,a[i] 与 a[k] 构成了最大盛水容器,容量为 C。

  1. 如果 a[i] <= a[k],则 C = a[i]*(k - i),那么我们现在来看一下,a[i] 和 a[j] 构成的盛水容器,容量如何,其容量为 a[i]*(j - i) > C,此时假设不成立!
  2. 同理,如果 a[i] > a[k],则 C = a[k]*(k - i),注意此时,由不等式的传递性可得a[j] 和 a[k] 的大小关系为 a[j] > a[k]。所以依然有 a[i] 和 a[j] 构成的盛水容器,容量为 a[i]*(j - i) > C,此时假设依然不成立!

综上可得,a[i] 不可能与 a[i+1,…,j-1] 之间的某个数构成最大盛水容器。证明结束!(移动 j 的情况同理证得)

最后再给出一道双指针例题:
给一个按升序排序的整数数组,寻找数组中和等于某个特定值的两个数,返回这两个数的下标。
示例的 Java 代码如下:

public static int[] twoSum(int[] a, int target){
	int i = 0, j = a.length - 1;
	while(true){
		if(target == a[i] + a[j]) return new int[]{i, j};
		if(a[i] + a[j] < target) ++i;
		else --j;
		if(i == j) return null;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值