经典面试题:盛最多水的容器(双指针法)

例题:
给你 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

这道题目简单来说就是x轴乘y轴能够得到的最大面积(y轴取较小的那一个)

这道题目采取双指针法解题(后面我们再讲解双指针法的正确性)
示例:[1,8,6,2,5,4,8,3,7]
分析:
首先,将左右指针分别放在数组左右两端。
面积公式就是:两个指针指向的数字中较小值∗指针之间的距离

此时有 最大容量: min (1,7) * 8 = 8 ⇒ min(nums[0],nums[8]) * (8-0)

此时我们要开是移动指针,我们可以分析得到我们应该移动较小的那个指针也就是左指针,如果我们移动较大的那个指针,因为前面较小的值没有变化,并且间隔减小,这个乘机就减小了。所以我们移动数字较小的那个指针。

所以,我们将左指针向右移动:[x,8,6,2,5,4,8,3,7]
容纳的水量为 min⁡(8,7)∗7=49。

由于右指针对应的数字较小,我们移动右指针:[x,8,6,2,5,4,8,3,x]
容纳的水量为 min⁡(8,3)∗6=18。

由于右指针对应的数字较小,我们移动右指针:[x,8,6,2,5,4,8,x,x]
此时可以容纳的水量为 min⁡(8,8)∗5=40。

两指针对应的数字相同,我们可以任意移动一个,例如左指针:[x,x,6,2,5,4,8,x,x]
容纳的水量为 min⁡(6,8)∗4=24。

由于左指针对应的数字较小,我们移动左指针,并且可以发现,在这之后左指针对应的数字总是较小,因此我们会一直移动左指针,直到两个指针重合。在这期间,对应的可以容纳的水量为:min⁡(2,8)∗3=6,min⁡(5,8)∗2=10,min⁡(4,8)∗1=4

所以从我们记录的值可以得出最大融水量为49

为什么我们双指针法是正确的(移动哪一个指针)
在我们选择移动指针的时候,我们无非就是两个选择:左指针和右指针。当我们移动较大的那个指针时,我们的值只会比原来的值小(两个指针指向的数字中较小值∗指针之间的距离),那么我们移动这个指针得到的值没有任何意义(要求最大值)。因为对于较小的这个指针我们已经获取到了它的最大值,我们可以舍弃掉这个左边界(这就是为什么要把左右指针放在左右两边)

所以我们应该移动指针较小的这个指针,这样相当于每次我们都排除掉一个边界,将问题的规模减小了1。被丢弃的那个位置相当于消失了。时的左右指针,就指向了一个新的、规模减少了的问题的数组的左右边界

代码

class Solution {
    public int maxArea(int[] height) {
        int left = 0,right = height.length-1;
        int ans = 0;
        while(left < right){
            int hei = Math.min(height[left],height[right]);
            ans = Math.max(ans, hei*(right-left));
            if(height[left] <= height[right]){
                left++;
            }else{
                right--;
            }
        }
        return ans;
    }
}
最多水容器问题是一个经典算法问题,通常被称为“最多水桶问题”。问题描述是这样的:给你一个长度为n的整数数组,每个元素代表一个木板的宽度,木板高度由左右两端确定,求两板之间能多少。要求编写一个函数,计算你能收集到的最多水量。 该问题可以通过双指针高效地解决。算法的基本思想是从数组的两端开始向中间扫描,找到能够装更多的区间,并更新最大容量。具体步骤如下: 1. 初始化两个指针,一个指向数组的开始,另一个指向数组的末尾,即i=0, j=n-1。 2. 计算当前的量,即宽度为j-i,高度为min(height[i], height[j]),其中height[i]和height[j]分别代表当前指针i和j所指的木板的高度。 3. 更新最大容量的变量,如果当前量大于最大容量,则最大容量等于当前量。 4. 移动指针,如果height[i] < height[j],则i向右移动一位(i++),反之则j向左移动一位(j--),因为木桶的容量取决于较短的木板高度。 5. 重复步骤2~4,直到两个指针相遇,此时已经扫描完所有可能的组合。 以下是该算法的C语言实现示例: ```c #include <stdio.h> int maxArea(int* height, int heightSize) { int i = 0, j = heightSize - 1; int maxWater = 0; while (i < j) { int width = j - i; int water = width * (height[i] < height[j] ? height[i++] : height[j--]); maxWater = water > maxWater ? water : maxWater; } return maxWater; } int main() { int height[] = {1, 8, 6, 2, 5, 4, 8, 3, 7}; int heightSize = sizeof(height) / sizeof(height[0]); printf("The maximum area is: %d\n", maxArea(height, heightSize)); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值