问题链接:https://oj.leetcode.com/problems/container-with-most-water/
问题描述:
Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such
that the container contains the most water.
Note: You may not slant the container.
API:public int maxArea(int[] height)
问题分析:这一题其实和排序过的Two sum是有相似的地方的,本质上都是dp和贪心算法的体现,但却也有不同之处。
最简单的想法当然就是brute force遍历全部的情况,时间是O(n^2),两层for循环即可。但是这肯定不是最优算法。
下面来分析一下,因为水池的容量是由长度,以及左右之间的短板所决定的。所以根据贪心算法的定义,首先给出两个指针,head = 0, tail = height.length - 1,然后头尾往中间缩。然后替换掉更短的那个板,也就是if(height[head] < height[tail]) head++,反之tail--。 根据这个算法,给出代码如下:
public int maxArea(int[] height) {
int head = 0, tail = height.length - 1, res = 0;
while(head < tail){
res = Math.max(res, (tail - head) * Math.min(height[head], height[tail]));
if(height[head] < height[tail])
head++;
else
tail--;
}
return res;
}关于贪心法,最复杂的并不是算法本身,而是算法适用性的证明,贪心算法比较好用以证明的方式是数学归纳或者反证法,下面给出反证法的说明:
首先给出证明来源,因为我思考了很久但并没有思考出证明的方法.......
https://oj.leetcode.com/discuss/1074/anyone-who-has-a-o-n-algorithm
下面,基于上面的连接,我给出自己的理解好了:
假设存在比我们给出的解更优的解,left_b和right_b,那么根据我们的解法,我们必然会首先到达left_b和right_b的其中一个,假设head先到达left_b好了(反之也一样的,不影响证明的过程),那么我们的tail指针此时还没有到达right_b,接下来根据我们的算法必然会出现两种情形的其中一种
1.tail一路向北,头也不回的就准备和我们的head汇合了。但此时肯定经过了right_b,如果left_b和right_b是更优解,那么必然也会被我们的算法找到。但事实上我们假定了这个解是更优的,所以矛盾了。
2. 在我们的算法里,tail到了某个点,假设是right_c,right_c > right_b,head就离开了我们的最优解left_b,这种情况是唯一有可能我们算法会错过最优解的合理解释。但这种方式也是行不通的,理由如下,首先,不用质疑,right_c - left_b 》 right_b - left_b,所以在长度上占优,而且我们还可以看到min(heights[left_b], heights[right_b]) <= min(heights[left_b], heights[right_c])。理由有点绕,但事实上是这样的:
首先head会离开left_b,是因为height[left_b] < height[right_c] 不满足而诞生的,所以min(heights[left_b], heights[right_c]) = heights[left_b]
而事实上,heights[right_b]此时就没有任何意义了,即使heights[right_b]为任意值,短板min(height[left_b], heights[right_b])也只能小于等于heights[left_b]
因此,left_b和right_b也不可能是最优解,和假设矛盾。
至此,贪心法便得证了。
1万+



被折叠的 条评论
为什么被折叠?



