LeetCode Top 100 Liked Questions 11. Container With Most Water (Java版; Medium)

welcome to my blog

LeetCode Top 100 Liked Questions 11. Container With Most Water (Java版; Medium)

题目描述

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 and n is at least 2.
Example:

Input: [1,8,6,2,5,4,8,3,7]
Output: 49

class Solution {
    public int maxArea(int[] height) {
        int n = height.length;
        int left = 0, right = n - 1;
        int max = 0;
        while(left<right){
            max = Math.max(max, Math.min(height[left], height[right])*(right-left));
            if(height[left]<height[right]){
                left++;
            }else{
                right--;
            }
        }
        return max;
    }
}
第二次做; 数组无序也能用双指针, 核心: 双指针的移动原则是什么? 舍弃当前边界中更短的边界, 为什么短边可以舍弃? 因为保留短边的话, 另一个指针再怎么移动也只能减少面积, 舍弃一条边相当于舍弃了O(N)种不行的方案; 这样做之所以能够找到最优解, 是因为双指针相当于用O(N)的时间复杂度考虑完了O(N^2)的搜索空间, 见下面的证明;
/*
数组无序, 如何使用双指针? 从两端向中间移动

存水高度取决于两个边界中较低的
*/
class Solution {
    public int maxArea(int[] height) {
        int n = height.length;
        int left=0, right=n-1;
        int res = 0;
        while(left<right){
            //注意求面积时宽度是right-left, 不是right-left+1
            int water = (right - left) *(Math.min(height[left], height[right])); 
            if(water > res)
                res = water;
            //如何移动柱子? 舍弃当前边界中更短的边界;  并不是说选取下一个更高的边界
            if(height[left]<height[right])
                left++;
            else{
                right--;
            }
        }
        return res;
    }
}
第一次做, 双指针, 每次移动都舍弃当前的短边, 为什么? 因为保留短边的话, 高最高就是短边的长度, 同时宽度会随着指针移动逐渐变小, 所以面积会变小; 只有舍弃当前的短边才有可能找到更长的边, 使得面积增大
class Solution {
    public int maxArea(int[] height) {
        int left=0, right=height.length-1;
        int max = 0;
        while(left<right){
            max = Math.max(max, (right - left) * Math.min(height[left], height[right]));
            //舍弃短边
            if(height[left]<height[right])
                left++;
            else
                right--;
        }
        return max;
    }
}
第一次做, 暴力
//暴力
class Solution {
    public int maxArea(int[] height) {
        int max=0;
        for(int i=0; i<height.length; i++){
            for(int j=i+1; j<height.length; j++){
                max = Math.max(max, (j-i)*Math.min(height[i], height[j]));
            }
        }
        return max;
    }
}
LeetCode双指针法证明
为什么短边可以舍弃? 因为保留短边的话, 另一个指针再怎么移动也只能减少面积
I know that some people are still having a hard time understanding this proof, but please re-read original proof a few times.
Here is my example hope it helps.

[4 (left) , 9, 12, 7 , 8, 14 (right) ] --------> this array is indexed from 1 to 6 and we looks at left and right and compare the value

So eliminate all pairs of index [1,2], [1,3],[1,4],[1,5] <- here the index[] means possible windows of solutions (4,9), (4,9,12), (4,9,12,7)...
Why? area of window [1,6] = (6 - 1) * MIN(4, 14) = 20
all the windows that have [1,2...5] even if all the numbers on the right are changed to infinity must be less than 20.
EX:
(5-1) * min(4, infinity) < 20 for all right indicies less than 6.
So this means its ok to exclude all windows starting with index 1

If you apply this at each step over and over again you can get an O(n) algorithm.
Hope this helps.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值