0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Leetcode上第11号问题:盛最多水的容器

算法与数据结构 来源:算法与数据结构 2020-05-06 10:35 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

Leetcode 上第 11 号问题:盛最多水的容器,是一道非常经典的问题。不久前,一个同学还告诉我,他去字节跳动面试,考了一模一样的原题。

这个问题本身很好理解:在坐标轴的每个坐标位置都放上了一系列长度不等的竖板。要求在这些竖板中选出两块,这两块竖板和坐标轴组成了一个“容器”。这个容器的底就是这两块竖板所在的坐标之间的距离;而高则是这两块竖板之间的较短者。所谓短板效应。

问题是希望找到两块竖板,使得这个“容器”的面积最大。

如果总共有 n 块木板可以选择的话,我们可以暴力枚举任意两块木板的组合,检查他们组成的容器面积,一共需要检查 n * (n - 1) / 2 对木板的组合。

如果会排列组合的同学,可以很轻易地使用组合公式得到这个结果,即:

C(n, 2) = n * (n - 1) / 2

即使不擅长排列组合的同学,也可以非常容易地通过程序来分析出这个结果。我们的暴力枚举的程序伪码是这样的:(其中数组 a 存储了 n 个木板的高度)

res=0; for(i=0;i< n; i ++)         for(j = i + 1; j < n; j ++){                 // 判断使用 a[i] 和 a[j] 作为木板组成的容器是否是更大的容器              // min(a[i], a[j]) 是容器的高度,即两块木板选短者                 // j - i 为容器的底                 res = max(res, min(a[i], a[j]) * (j - i));         } return res;

在上面的循环中,res 一共被比较计算了几次?

可以想象,当 i == 0 的时候,j 的取值范围是从 1 到 n-1,内循环一共计算了 n-1 次;

当 i == 1 的时候,j 的取值范围是从 2 到 n-1,内循环一共计算了 n-2 次;

当 i == 2 的时候,j 的取值范围是从 3 到 n-1,内循环一共计算了 n-3 次;

以此类推...

i 最大取值为 n - 2,此时 j 的取值为 n-1,内循环只计算了 1 次。

所以,整体,内循环计算的次数,就是 1 + 2 + 3 + ... + (n-3) + (n-2) + (n-1)。

这是一个等差数列求和,一共 n-1 项,首项为 1,末项为 n-1。带入等差数列求和公式,就是 n * (n - 1) / 2。

很显然,这样暴力枚举,我们的算法时间复杂度是 O(n^2) 级别的。

实际上,这个问题有 O(n) 级别的解法,也就是大名鼎鼎的双指针解法,思路是这样的:

首先,使用 left 和 right 两个指针,分别指向最左边的木板 a[0] 和最右边的木板 a[n-1]。这样,left 和 right 就构成了一个容器。这个容器的面积,是我们的初始值。

下一步,我们只需要看 left 对应的木板和 right 对应的木板谁小,就好了。如果 left 更小,那么就 left ++,也就是下一步去检查 a[1] 和 a[n - 1] 组成的容器是否更大?如果 right 更小,那么就 right --,也就是看 a[0] 和 a[n - 2] 组成的容器是否更大?这个过程以此类推,如果发现了更大的容器,就更新结果。

算法伪码大概是这样的:

l=0,r=n-1,res=0; while(l< r){         // 判断使用 a[l] 和 a[r] 作为木板组成的容器是否是更大的容器         res = max(res, min(a[l], a[r]) * (r - l));          if(a[l] < a[r]) l ++;         else r --; } return res;

可以看出来,这个过程,或者 left ++,或者 right --,木板之间的距离越来越小。直到 left 和 right 碰上,也就是两块木板重合了,容器的底为 0,此时,算法结束。

这个算法的复杂度是 O(n) 的。因为整个算法中,每一个木板都或者被 left 指针指过一次,或者被 right 指针指过一次,直到 left 和 right 汇合。

对应的,res 一共被计算了 n-1 次。因为两个木板才能形成一个容器。使用这种方式,n 个木板,一共组成了 n-1 个容器。

这个算法看起来非常简单,但是,一个很致命的问题是:这个算法为什么是正确的?

一个直观的想法是:每次不管是 left 右移,还是 right 左移,容器的底都会减一。由于容器的底减小了,所以,如果我们要想得到更大的面积,就要让容器的高变大。整个容器的高是由最短的木板决定的,所以我们将两个木板中最短的那一个做改变,才有可能得到一个更大的容器。

这个解释模模糊糊说得通,但似乎并不是那么严格。关键在于,这个解释没有说明:这个算法为什么没有漏掉一个可能的更大面积的容器?

Leetcode 的讨论区有很多关于这个算法的正确性的讨论,但我觉得大多数叙述的语言过于理论化了。也有同学在我的课程问答区问过我这个问题,所以,我写了这篇文章,尝试阐述一下这个问题。

我们来看初始的时候,left 指向 a[0],right 指向 a[n-1]。我们假设 a[0] 是小于 a[n-1] 的,即 a[0] < a[n-1]。那么下一步,根据我们的算法,就是 left ++,即 left 下一步指向了 a[1]。

这意味着什么?这就意味着,使用 a[0] 和 a[n-2];使用 a[0] 和 a[n-3];使用 a[0] 和 a[n-4];.... ;使用 a[0] 和 a[1],这些木板的组合,我们都直接跳过去了,不去计算了。

换句话说,因为我们直接 left ++ 了,所以所有的以 a[0] 为左边木板的其他组合,都不看了。

为什么可以这样?

还记得我们的假设吗?a[0] 是小于 a[n-1] 的。所以,此时,整个容器的高度,是由 a[0] 决定的。因为,如果右边板的高度大于 a[0],我们取短板,容器的高度还是 a[0];如果右边的高度小于 a[0],那么容器的高度比 a[0] 还要小。

而对于其他的以 a[0] 为左边木板的组合:a[0] 和 a[1],a[0] 和 a[2],a[0] 和 a[3],...,a[0] 和 a[n-2],底的长度都比 a[0] 和 a[n-1] 更小。而高度又不会超过 a[0],所以,面积一定是更小的,我们就可以直接排除掉!

那么这个过程,我们一下子排除了多少组组合呢?答案是,左边是 a[0],右边是 a[1] ... a[n-2],一共 n-2 组组合,直接被我们扔掉了。

当然,如果我们假设 a[0] > a[n-1],这个逻辑同样成立,只不过我们扔掉的组合,右边固定为 a[n-1],左边是 a[1] 到 a[n-2],还是 n-2 个组合。

现在,假设我们的 left 指向 1 了,right 还是 n-1。再假设,这次是 a[1] > a[n-1] 了。那么,按照我们的算法,就应该是 right-- 了。

这次,有了上面的分析,相信大家就都理解了,我们不需要比较 a[2] 和 a[n-1];a[3] 和 a[n-1];a[4] 和 a[n-1];...;a[n-3] 和 a[n-1],a[n-2] 和 a[n-1],这些组合了。

为什么?因为此时,a[1] 和 a[n-1] 这个组合中,容器的高度是由右边的板 a[n-1] 决定的。那么剩下的以 a[n-1] 为右侧板的所有容器,高度不可能大于 a[n-1] 了,而底却在缩小,所以,这些组合都可以直接扔掉,不计算了。

那么这次,我们扔掉了多少个组合?答案是右边固定为 a[n - 1],左边是 a[2], a[3],...,a[n-2],一共 n-3 个组合!

相信大家可以看出规律来了。我们每次左指针或者右指针移动一次,其实都是扔掉了若干组合,不再需要比较了。

第一次移动,扔掉了 n-2 个组合;第二次移动,扔掉了 n-3 个组合;第三次移动,将扔掉 n-4 个组合,依次类推,直到最后一次移动,扔掉 1 个组合。

那么,我们在这个过程中,总共扔掉了多少组合?就是 1, 2, 3, ... , n-4, n-3, n-2 的和。大家可以看出来,这又是一个等差数列。首项是 1,末项是 n-2,一共 n-2 项。

带入等差数列求和公式,我们一共扔掉了 (n-1)*(n-2)/2 这么多个组合,不用去考虑。

现在,大家就可以计算一下了。回忆一下上面的叙述:

我们一共扔掉了 (n-1)*(n-2)/2 这么多组合,只计算了 n-1 这么多组合。

把他们加起来,是多少?

答案是 n * (n - 1) / 2!

大家回忆一下,这个数字正好就是 n 块木板,抽出两块,组成容器的所有可能方案!

C(n, 2) = n * (n - 1) / 2!

那么这也就证明了,我们的双指针算法,比较了 n-1 组木板,扔掉了 (n-1)*(n-2)/2 组木板,合在一起,已经完整地考虑了所有 n * (n - 1) / 2 组木板的组合了。

我们这个过程,不会漏掉任何一个组合,最终找到的解,一定是最优解!

怎么样?是不是觉得这个证明理解起来并不难?

值得一提的是,虽然我们说这个问题是双指针的问题,但其实,在算法设计上,我们使用了贪心的思想。即每次把最短木板对应的所有其余组合都扔掉了。

而对于贪心算法来说,最大的特点就是:通常代码都会比较简单,但要想证明贪心的正确性,会比较费劲。这个问题就是一个很好的例子。

实际上,在 Leetcode 上,还有很多贪心的问题,拥有这样的特点。以后有机会,可以再向大家介绍。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 算法
    +关注

    关注

    23

    文章

    4760

    浏览量

    97144
  • 容器
    +关注

    关注

    0

    文章

    521

    浏览量

    22812
  • leetcode
    +关注

    关注

    0

    文章

    20

    浏览量

    2517

原文标题:优雅地证明 盛水容器问题

文章出处:【微信号:TheAlgorithm,微信公众号:算法与数据结构】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    昌亮相2025深圳核博会

    近日,2025核博会在深圳国际会展中心(福田)圆满举办。作为全球核能领域的重要交流平台,本届盛会聚焦核能技术创新与产业协同,汇集了众多行业专家与企业代表。深圳市华昌科技实业股份有限公司(股票代码
    的头像 发表于 11-19 10:51 248次阅读

    智能嵌入式eMMC E210系列斩获2025年度嵌入式存储产品金奖

    11月18日, 一年一度中国数据与存储峰会在北京顺利召开,备受关注的2025存储风云榜同期揭晓。作为领先的存储控制器与解决方案提供商,芯智能受邀参会,凭借自主研发的嵌入式eMMC E210系列
    的头像 发表于 11-18 17:17 1201次阅读
    芯<b class='flag-5'>盛</b>智能嵌入式eMMC E210系列斩获2025年度嵌入式存储产品金奖

    上海永铭电子诚邀您莅临深圳CPEEC*CPSSC展,共探高性能电容器创新应用新未来

    上海永铭电子将于11月8日至9日精彩亮相深圳CPEEC*CPSSC展会,展位位于20馆E16。届时,永铭将集中展示在新能源汽车、AI服务器、光伏储能、电机驱动(机器人/无人机/伺服驱动)等关键领域
    的头像 发表于 11-07 13:48 395次阅读
    上海永铭电子诚邀您莅临深圳CPEEC*CPSSC展,共探高性能电<b class='flag-5'>容器</b>创新应用新未来

    昌DeepSense深度感测大模型通过生成式人工智能服务备案

    近日,深圳市华昌科技实业股份有限公司(以下简称“华昌”)的“DeepSense深度感测大模型”在历经属地网信办初审、中央网信办终审及六大部委意见征询后,通过广东省生成式人工智能服务备案(备案
    的头像 发表于 09-08 14:49 1573次阅读

    季丰电子与剑科技达成战略合作

    8月29日,在剑科技成立20周年庆祝活动上,季丰电子与剑科技举行了正式的战略合作签约仪式。
    的头像 发表于 09-01 18:08 921次阅读

    智能入选2025中国创新品牌500强

    8月8-11日,第十九届中国品牌节在深圳顺利召开,同期,“2025中国创新品牌500强”榜单发布。芯智能科技(湖南)有限公司(以下简称“芯智能”)凭借在存储领域的自主创新实力和市场表现,成功入围2025中国创新品牌500强。
    的头像 发表于 08-12 15:55 1547次阅读

    英飞特点亮广州地铁11线

    随着广州地铁11线正式通车,这条覆盖33座车站、全长超43公里的华南最长地铁环线全面投入运营。
    的头像 发表于 07-22 14:40 702次阅读

    集团2025年数字化建设项目正式启动

    为统一战略认知、凝聚执行合力,近日,航2025年数字化建设项目启动会在深圳总部顺利召开。航高层领导及项目团队成员出席本次活动。会议标志着航集团2025年数字化建设项目正式启动。
    的头像 发表于 07-18 10:20 750次阅读

    昌亮相2025亚欧商博会

    此前,6月26日至30日,2025(中国)亚欧商品贸易博览会(以下简称“商博会”)在乌鲁木齐隆重举行。华昌(展位:J21)携旗下专为新型电力系统和新能源产业链量身打造的专业测试测量仪器与解决方案亮相。
    的头像 发表于 07-07 17:41 650次阅读

    昌精彩亮相SNEC 2025

    此前,6月11日-13日,第十八届国际(2025)太阳能光伏与智慧能源大会暨展览会在上海国家会展中心举行。华昌携旗下专为新能源领域打造的专业测试测量仪器和专业配套解决方案亮相4.1H-B515展位,全力赋能行业伙伴加速迈向智能、可持续的未来能源体系。
    的头像 发表于 06-23 18:01 959次阅读

    查看an70707文档,为什么它的指导电源电容器使用0.01uf和0.1uf的电容器

    (C11) 0.01 μF 和 0.1 μF 阅读指南文档后,我认为一定有一些重要的原因,但是当我查看SuperSpeed_Explorer_Kit的bom文件时,它使用了公差为10%的电容器。 从我的角度来看,使用两个电容器
    发表于 05-14 08:26

    凝胶拉伸试验机:材料性能的洞察者

    凝胶,作为一种神奇的亲水性聚合物材料,能吸收大量水分,呈现出柔软、透明且富有弹性的凝胶状。因其独特性能,在生物医学、组织工程、药物输送、柔性电子等诸多前沿领域展现出巨大应用潜力。而深入探究凝胶
    的头像 发表于 04-28 10:37 446次阅读
    <b class='flag-5'>水</b>凝胶拉伸试验机:材料性能的洞察者

    【重磅喜讯】再获国家认可!赛检测通过CNAS复评审

    (CNAS)委托评审专家现场评审,赛检测现有的127个检测标准(方法),全部通过复评评审,还推荐了申请变更的11个(其中,电磁兼容7个,可靠性4个)检测标准(方法
    的头像 发表于 03-21 17:40 806次阅读
    【重磅喜讯】再获国家认可!赛<b class='flag-5'>盛</b>检测通过CNAS复评审

    投资5亿元,高端半导体装备项目签约无锡

    日前,高端半导体装备项目签约落地惠山,未来将入驻即将投用的惠山先进制造产业园,为惠山半导体产业能级跃升增添强劲动能。
    的头像 发表于 01-04 10:43 2221次阅读

    铂科技FlexDDS-NG相参信号源:量子光学研究多通道波形发生器

    铂科技FlexDDS-NG能够在单个机箱中提供最多12个独立的射频输出通道和ADC采集通道,输出频率高达400MHz,满足了高密度实验设置的需求。
    的头像 发表于 12-24 13:33 1011次阅读
    <b class='flag-5'>盛</b>铂科技FlexDDS-NG相参信号源:量子光学研究多通道波形发生器