[LeetCode]#4盛最多水的容器:双指针法及其证明

问题

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

说明:你不能倾斜容器,且 n 的值至少为 2。
在这里插入图片描述

图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例:

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

算法

我们在数组中使用两个指针,一个放在开始,一个置于末尾。在每一步中,我们将指向较短线段的指针向较长的线段那端移动;同时,我们记录下所有步骤里最大的面积: maxSquare

证明

我们将所有情况用一棵递归树列出,如下:
在这里插入图片描述
m , n 表示前后指针,H[m] 表示位置 m 处的高度,n 是输入的数据长度。S(m,n) = min(H[m],H[n]) * (n-m)(m,n) 对的面积。h[m,n] 表示当前位置的树高, h = n-m

红色圈出部分为双指针法可能的一条路径(路径并不唯一)。

这意味着:在双指针路径的红圈外任意一个情况的 S(m,n) 均小于 maxSquare

下面我们来证明是否一定如此。

反证法

假设,存在一个双指针路径之外的 S(m,n) > maxSquare。则:
S ( m , n )    =    { H ( m ) ∗ h      H ( m ) < H ( n ) H ( n ) ∗ h      H ( n ) < H ( m ) S\left(m,n\right)\;=\;\left\{\begin{array}{l}H(m)\ast h\;\;H(m)<H(n)\\H(n)\ast h\;\;H(n)<H(m)\end{array}\right. S(m,n)={H(m)hH(m)<H(n)H(n)hH(n)<H(m)
我们观察递归树可以发现,当 (m,n) 在双指针路径的左边时,在路径上必定存在 (m,X) (可能会有多个),且 (m,X)(m,n) 的上方;同理,当 (m,n) 在双指针路径的右边时,在路径上也必定存在 (X,n) ,且 (X,n)(m,n) 的上方。

(1) 对于 (m,n) 在路径左边的情况

根据观察,由于路径上存在 (m,X) ,且 (m,X)(m,n) 的上方,即:h[m,X]>h[m,n]

由于若对任意一个 (m,X)H(X)<H(m) 恒成立的话,(m,n) 将不会在路径的左边,而是在路径中。故在路径上必定存在一个且仅且一个 (m,α) 满足: H(α)>H(m)S(m,α) = H(m) * h[m,α]

由于h[m,α]>h[m,n] ,而若 H(m)<H(n), S(m,n) = H(m) * h[m,n] < S(m,α) = H(m) * h[m,α],这与我们的假设 S(m,n) > maxSquare 不符合。

所以我们可以得到:H(α)>H(m)>H(n)S(m,n) = H(n) * h(m,n) 。而 h[m,α]>h[m,n],即:S(m,α)>S(m,n),仍然与我们的假设 S(m,n) > maxSquare 不符合。故假设不成立!

(2) 对于 (m,n) 在路径右边的情况

同理就略了…

由此,我们可以确定双指针方法是正确的。代码如下:

/**
 * @param {number[]} height
 * @return {number}
 */
var maxArea = function(height) {
    let i = 0, j = height.length-1;
    let square, max = 0;
    while(j-i >= 1){
        if(height[i]>height[j]){
            square = height[j] * (j-i);
            j--;
        }else{
            square = height[i] * (j-i);
            i++;
        }
        max = Math.max(square,max);
    }
    return max;
};
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值