Leetcode第11题(盛最多水的容器)解释为什么不会错过最优解。

题目描述

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

说明:你不能倾斜容器,且 n 的值至少为 2。

 

 分析

如果使用暴力搜索,

  • 时间复杂度:O(n^2),计算所有种高度组合的面积。
  • 空间复杂度:O(1),使用恒定的额外空间。

使用双指针搜索:

我们在由线段长度构成的数组中使用两个指针,一个放在开始,一个置于末尾。 此外,我们会使用变量 maxarea 来持续存储到目前为止所获得的最大面积。 在每一步中,我们会找出指针所指向的两条线段形成的区域,更新 maxarea,并将指向较短线段的指针向较长线段那端移动一步。

代码如下:

class Solution:
	def maxArea(self, height: List[int]) -> int:
		i=0
		j=len(height)-1
		res=0 # 使用双指针
		while i<j:
			h=min(height[i],height[j])
			res=max(res,(j-i)*h)
			if height[i]>height[j]:
				j=j-1
			else:
				i=i+1
		return res

那么,为什么这种双指针搜索不会错过最优解呢?

我们从最开始,i=0,j=n-1开始分析,res表示容器的体积,一共两种情况:

(1)第一根高度比最后一根高度要矮,这个时候要把当前的容积存下来,并把左指针右移一位 ,这个时候之后就不用考虑第一根柱子了,为什么呢?

        因为固定左侧指针为第一根柱子不动时,对于第一根柱子来说,另一根柱子选择最后一根柱子已经是使容器体积最大,也即res最大的方案了。所以我们把这个容积res=(n-1)*height[0]存下来之后,就不需要考虑第一根柱子了,不像暴力搜索中,两层循环。这又是为什么呢?我们也分两种情况考虑。

        (a)如果选取的右侧柱子比第一根高,那么不论右侧柱子是哪一根,容器的高度h肯定取较短的那一侧高度,也就是第一根柱子高度height[0],接下来只需要看容器的宽度,也就是(j-i)的大小就好了,显然n-1是最大的宽度了,所以此时右指针是n-1是最优选择;(b)如果选取的右侧柱子比第一根矮,那么h<height[0]还小,而且容器的宽度比n-1也小,所以容积肯定也比(n-1)*height[0]小了。

        所以第一种情况下,最大的容积res=(n-1)*height[0],把这个值保存下来,想要看还有没有比这个res还大的情况,第一根柱子就不用考虑了,故把i加一,从第二根柱子开始重复这个比较过程;

(2)第一根高度比最后一根高度要高:那么跟上面这种情况类似,我们从后往前看,从最后一根柱子的视角来看,另一根柱子选择第一根柱子是使得res最大的选择,接下来把res保存下来,把j减一,就可以不用考虑最后一根柱子了。

从而,可以实现时间复杂度为O(n)的算法了,即只要一次遍历即可。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值