leetcode 11. 盛最多水的容器
- 1. leetcode 11. 盛最多水的容器
- 1. 题目详情
- 1. 原题链接
- 2. 基础框架
- 2. 解题思路
- 1. 题目分析
- 2. 算法原理
- 3. 时间复杂度
- 3. 代码实现
- 4. 知识与收获
1. leetcode 11. 盛最多水的容器
1. 题目详情
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。
示例 1:
输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例 2:
输入:height = [1,1]
输出:1
提示:
n == height.length
2 <= n <= 105
0 <= height[i] <= 104
1. 原题链接
leetcode 11. 盛最多水的容器
2. 基础框架
● Cpp代码框架
class Solution {
public:int maxArea(vector<int>& height) {}
};
2. 解题思路
1. 题目分析
( 1 ) (1) (1) 题目要求的是水池的最大容积
2. 算法原理
( 1 ) (1) (1) 首先会想到使用暴力解法,使用两层for循环枚举出所有的情况,找出最大水的容积。但是时间复杂度 O ( n 2 ) O(n^2) O(n2)题目不给过,需要找规律优化效率。
( 2 ) (2) (2) 使用对撞双指针算法:指针left
指向数组第一个元素,指针right
指向数组最后一个元素;此时容积可表示为 v = ( r i g h t − l e f t ) ∗ m i n ( h e i g h t [ l e f t ] , h e i g h t [ r i g h t ] ) v=(right - left) * min(height[left], height[right]) v=(right−left)∗min(height[left],height[right])
( 3 ) (3) (3) 假设初始时 h e i g h t [ l e f t ] < h e i g h t [ r i g h t ] height[left] < height[right] height[left]<height[right]:我们们的目的是找出水的最大容积 v v v。首先不管是 l e f t left left往左移动,还是 r i g h t right right往右移动, ( r i g h t − l e f t ) (right - left) (right−left)一定是减小的;
当前 h e i g h t height height较小的是 h e i g h t [ l e f t ] height[left] height[left],那么如何确定是 l e f t left left向右移动还是 r i g h t right right向左移动呢?
( 4 ) (4) (4) 假设是 l e f t left left向右移动(right不变):对于移动后的最小 h e i g h t height height就有两种情况:
1.left移动后的 h e i g h t height height<=原先的 h e i g h t height height,此时 m i n ( h e i g h t [ l e f t ] , h e i g h t [ r i g h t ] ) min(height[left],height[right]) min(height[left],height[right])是不变或减小的,那么 v v v一定是减小的;
2.left移动后height>原先的 h e i g h t height height,此时 m i n ( h e i g h t [ l e f t ] , h e i g h t [ r i g h t ] ) min(height[left], height[right]) min(height[left],height[right])是增大的(增大之后也不会超过 h e i g h t [ r i g h t ] height[right] height[right],因为是选择较小的 h e i g h t height height计算),那么 v v v就可能是增大的。
( 5 ) (5) (5) 假设是 r i g h t right right向左移动(left不变):移动之后 h e i g h t [ r i g h t ] height[right] height[right]不管是增大、不变、还是减小, m i n ( h e i g h t [ l e f t , h e i g h t [ r i g h t ] ) min(height[left,height[right]) min(height[left,height[right])的值均不超过移动之前的值,即 v v v一定是减小的。
( 6 ) (6) (6) 综上,移动 h e i g h t height height较大的一方时, v v v不会超过当前的值;移动 h e i g h t height height较小的一方才可能得到更大的 v v v。
3. 时间复杂度
O ( n ) O(n) O(n)
左右双指针 l e f t left left和 r i g h t right right对撞而走,直到相遇结束,最终共同遍历了一遍整个数组。
3. 代码实现
class Solution {
public:int maxArea(vector<int>& height) {// v = s * hint l = 0, r = height.size() - 1;int maxWater = 0;while(l < r){int v = (r - l) * min(height[l], height[r]);maxWater = max(maxWater, v);if(height[l] > height[r]){r--;}else{l++;}}return maxWater;}
};
4. 知识与收获
( 1 ) (1) (1) 双指针是非常优秀的一种算法,常常使算法时间复杂度降低一维。
( 2 ) (2) (2) 常使用的有两种形式:
对撞双指针
,常见于数组中,核心思想来自快排。左指针left
指向起始元素,右指针right
指向最后一个元素。在循环中判断某些条件让左指针left
向右移动,右指针right
向左移动,直到left
和right
相遇停下来。
快慢双指针
,又叫龟兔赛跑法
,常见于数组、链表中,典例就是判断链表是否有环
。定义快慢指针slow
和fast
,通过让快慢指针分别以不同的速度移动来达到我们的目的。一般是快指针fast
一次走多步,慢指针slow
一次走一步。
( 3 ) (3) (3) 双指针算法是一种思想,不局限于数组或链表。双指针不一定非要是定义两个指针,也可以是下标。
T h e The The E n d End End