Cool说丨力扣11

简介: 11. 盛最多水的容器

11. 盛最多水的容器

给定 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

第一版,速度太慢

   intmaxArea(vector<int>&height) {

   intlen=height.size();

   intmostWater=0;

   for (inti=0,row,col; i<len; ++i)

   {

       for (intj=i+1; j<len; ++j)

       {

           row=j-i;

           col=min(height[i], height[j]);

           mostWater=row*col>mostWater?row*col : mostWater;

       }

   }

   returnmostWater;  

   }

执行用时 :1640 ms, 在所有 C++ 提交中击败了9.51%的用户

内存消耗 :9.9 MB, 在所有 C++ 提交中击败了65.57%的用户

第二版 双指针,很快

   intmaxArea(vector<int>&height) {

   inthigh=height.size()-1,low=0;

   intmostWater=0,temp;

   while (low<high)

   {

       temp= (high-low) *min(height[low], height[high]);

       mostWater=mostWater>temp?mostWater : temp;

       if (height[low] <=height[high]) low++;

       elsehigh--;

   }

   returnmostWater;

   }

执行用时 :16 ms, 在所有 C++ 提交中击败了97.32%的用户

内存消耗 :9.8 MB, 在所有 C++ 提交中击败了74.86%的用户

官方题解:

https://leetcode-cn.com/problems/container-with-most-water/solution/sheng-zui-duo-shui-de-rong-qi-by-leetcode/

最初我们考虑由最外围两条线段构成的区域。现在,为了使面积最大化,我们需要考虑更长的两条线段之间的区域。如果我们试图将指向较长线段的指针向内侧移动,矩形区域的面积将受限于较短的线段而不会获得任何增加。但是,在同样的条件下,移动指向较短线段的指针尽管造成了矩形宽度的减小,但却可能会有助于面积的增大。因为移动较短线段的指针会得到一条相对较长的线段,这可以克服由宽度减小而引起的面积减小。

比较经典的介绍

思路:算法流程: 设置双指针 ii,jj 分别位于容器壁两端,根据规则移动指针(后续说明),并且更新面积最大值 res,直到 i == j 时返回 res。

指针移动规则与证明: 每次选定围成水槽两板高度 h[i]h[i],h[j]h[j] 中的短板,向中间收窄 11 格。以下证明:

设每一状态下水槽面积为 S(i, j)S(i,j),(0 <= i < j < n)(0<=i<j<n),由于水槽的实际高度由两板中的短板决定,则可得面积公式 S(i, j) = min(h[i], h[j]) × (j - i)S(i,j)=min(h[i],h[j])×(j−i)。在每一个状态下,无论长板或短板收窄 11 格,都会导致水槽 底边宽度 -1−1:若向内移动短板,水槽的短板 min(h[i], h[j])min(h[i],h[j]) 可能变大,因此水槽面积 S(i, j)S(i,j) 可能增大。若向内移动长板,水槽的短板 min(h[i], h[j])min(h[i],h[j]) 不变或变小,下个水槽的面积一定小于当前水槽面积。因此,向内收窄短板可以获取面积最大值。换个角度理解:若不指定移动规则,所有移动出现的 S(i, j)S(i,j) 的状态数为 C(n, 2)C(n,2),即暴力枚举出所有状态。在状态 S(i, j)S(i,j) 下向内移动短板至 S(i + 1, j)S(i+1,j)(假设 h[i] < h[j]h[i]<h[j] ),则相当于消去了 {S(i, j - 1), S(i, j - 2), ... , S(i, i + 1)}S(i,j−1),S(i,j−2),...,S(i,i+1) 状态集合。而所有消去状态的面积一定 <= S(i, j)<=S(i,j):短板高度:相比 S(i, j)S(i,j) 相同或更短(<= h[i]<=h[i]);底边宽度:相比 S(i, j)S(i,j) 更短。因此所有消去的状态的面积都 < S(i, j)<S(i,j)。通俗的讲,我们每次向内移动短板,所有的消去状态都不会导致丢失面积最大值 。复杂度分析:

时间复杂度 O(N)O(N),双指针遍历一次底边宽度 NN 。空间复杂度 O(1)O(1),指针使用常数额外空间。

目录
相关文章
|
人工智能 C# C++
Cool说丨力扣153、454
153. 寻找旋转排序数组中的最小值 454. 四数相加 II
100 1
|
C# C++
Cool说丨力扣287/792/378
关注博主,获取更多知识
83 0
|
C# C++ 索引
Cool说丨力扣162
162. 寻找峰值
61 0
|
存储 C# C++
Cool说丨力扣29/34
关注博主。获取更多知识
73 0
|
存储 C# C++
Cool说丨力扣392
392. 判断子序列
49 0
|
C# C++
Cool说丨力扣744、704
744. 寻找比目标字母大的最小字母 704. 二分查找
68 0
|
C#
Cool说丨力扣475
475. 供暖器
84 0
|
机器学习/深度学习 算法 C#
Cool说丨力扣202
202. 快乐数
77 0
|
C#
Cool说丨力扣167
167. 两数之和 II - 输入有序数组
46 0
|
C# C++
Cool说丨力扣374、441
441. 排列硬币 374. 猜数字大小
59 0

热门文章

最新文章