专题1 - 双指针 - leetcode 11. 盛最多水的容器

在这里插入图片描述

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=(rightleft)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) (rightleft)一定是减小的;
当前 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 * h
        int 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向左移动,直到leftright相遇停下来。
快慢双指针,又叫龟兔赛跑法,常见于数组、链表中,典例就是判断链表是否有环。定义快慢指针slowfast,通过让快慢指针分别以不同的速度移动来达到我们的目的。一般是快指针fast一次走多步,慢指针slow一次走一步。
( 3 ) (3) (3) 双指针算法是一种思想,不局限于数组或链表。双指针不一定非要是定义两个指针,也可以是下标。


T h e The The E n d End End

  • 31
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

re怠惰的未禾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值