11. Container With Most Water(盛水最多的容器)解法(C++ & 注释)

1. 题目描述

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

题目链接:中文题目英文题目

2. 暴力解法(Brute Force, Time Limit Exceeded)

2.1 解题思路

直接遍历所有的数对,然后求最大的面积,应该是第一眼就能想到的方法,只是这个方法时间复杂度为O(n^2),当数组包含大量数字时,该方法超时。

2.2 实例代码

class Solution {
public:
    int maxArea(vector<int>& height) {
        int maxArea = 0, len = height.size();
        for (int i = 0; i < len - 1; i++) {
            for (int j = i + 1; j < len; j++) {
                maxArea = max(maxArea, (j - i) * min(height[i], height[j]));
            }
        }

        return maxArea;
    }

2. 双指针法(Two Pointer Approach)

2.1 解题思路

那我们能不能设置左指针(left = 0),和右指针(right = 数组长度 - 1),然后从外向里找到最大的面积呢?回答这个问题,我们需要解决两个:1. 怎么移动左右指针;2. 这种移动方法为什么一定能找到最大面积,而不会跳过它?

首先,我们把面积(S)公式总结一下。对于i和j位置代表的木板高度ai和aj,我们有如下的面积公式:

S = (j - i) * min(ai, aj);i < j

此时,因为面积取决于ai和aj两者之中最小的那个,所以我们要尽可能的让ai和aj尽可能的取到更大的值,所以这种思路下,如果ai < aj,我们让i往右走,即i + 1,让ai尽可能大;反之,当ai >= aj,我们让j往左走,即j - 1,让aj尽可能大;但是,我们就遇到了两个问题:1)j - i的距离如何保证最大?2)为什么不能反方向走呢?

既然如此,我们把上述两种情况分别讨论:

1.ai < aj
首先,利用条件ai < aj,S = (j - i) * min(ai, aj) = (j - i) * ai。这种情况下,我们假设i往右走,即i + 1,那为什么不让j往左走呢?即j - 1,我们假设一下j - 1,也有两种情况:

当ai <= aj - 1:

S1 = (j - i - 1) * min(ai, aj) = (j - i - 1) * ai;

当ai > aj - 1:

S2 = (j - i - 1) * min(ai, aj) = (j - i - 1) * aj - 1;

我们可以看到前部分(j - i - 1)一定比(j - i)小,所以当ai <= aj - 1,S > S1;当ai > aj - 1,S > S2;因而无论aj - 1大于等于还是小于ai,S都是大于等于新的面积,所有j没有必要往左走。

2.ai >= aj
这里可以用和面上相同的方法得到:无论ai + 1大于等于还是小于aj,S都是大于等于新的面积,所以此时i没有必要往右走。

所以经过上述证明,使用双指针的方法,一定可以找到最大面积。

2.2 实例代码

class Solution {
public:
    int maxArea(vector<int>& height) {
        int maxArea = 0, left = 0, right = height.size() - 1;
        while (left < right) {
            maxArea = max((right - left) * min(height[left], height[right]), maxArea);
            if (height[left] > height[right]) right--;
            else left++;
        }

        return maxArea;
    }
};

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值