一分钟解决一道高频面试算法题——盛水最多的容器(双指针最优解)

一、题目描述------盛水最多的容器

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0)(i, height[i])

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明: 你不能倾斜容器。

示例 1:

css 复制代码
输入: [1,8,6,2,5,4,8,3,7]
输出: 49 
解释: 图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例 2:

css 复制代码
输入: height = [1,1]
输出: 1

提示:

  • n == height.length
  • 2 <= n <= 105
  • 0 <= height[i] <= 104

二、题解(双指针)

没错 哥们又超时了(反面案例)

js 复制代码
var maxArea = function(height) {
    let ans=0;
    for(let i=0;i<height.length;i++){
        for(let j=i+1;j<height.length;j++){
            ans=Math.max(ans,(j-i)*Math.min(height[i],height[j]));
        }
    }
    return ans;
};

这个解法是O(N2)的时间复杂度,把所有组合遍历了一遍,这里超时了就不再详解了

双指针解法(最优解)

js 复制代码
/**
 * @param {number[]} height
 * @return {number}
 */
var maxArea = function(height) {
    let left = 0;  // 左指针
    let right = height.length - 1;  // 右指针
    let maxWater = 0; // 记录最大水量

    while (left < right) {
        // 计算当前容器的宽度和高度
        const width = right - left;
        const minHeight = Math.min(height[left], height[right]);

        // 计算当前容器的容量
        const currentWater = width * minHeight;

        // 更新最大水量
        maxWater = Math.max(maxWater, currentWater);

        // 移动指针:总是移动高度较小的那个指针
        if (height[left] < height[right]) {
            left++;
        } else {
            right--;
        }
    }

    return maxWater;
};

核心思路

通过双指针逼近,不断寻找更大的容器面积,并最终找到最大值。

  1. 双指针,界定搜索范围: leftright 指针分别指向数组的首尾,它们界定了当前考虑的容器的左右边界。

  2. 面积计算,比较大小: 在每次循环中,计算 leftright 指针所形成的容器的面积,并与当前已知的最大面积 maxWater 进行比较,更新 maxWater

  3. 移动策略,缩小搜索空间: 这是最关键的一点。代码总是移动高度较小的那个指针。 这个策略基于以下观察:

    • 容器的面积由宽度和高度决定,而高度是 leftright 指针指向的两个高度中的较小值。
    • 如果移动较高的那个指针,容器的宽度会减小,而高度最多只能保持不变,因此面积不可能增大。
    • 相反,如果移动较低的那个指针,虽然宽度会减小,但高度有可能增加,从而有可能找到更大的面积。
  4. 迭代逼近,找到最优解: 通过不断地移动指针,逐步缩小搜索范围,从而遍历所有可能的容器,并找到面积最大的那个。

更直观地理解移动策略:

假设 height[left] < height[right],这意味着当前容器的面积受限于 height[left]。 移动 left 指针的目的是:

  • 寻找一个更大的 height[left],这样新的容器的高度才有可能增加,从而有可能得到更大的面积。
  • 即使新的 height[left] 比原来的小,但是如果 height[left]height[right]的差值变小,整体的面积也可能变大。

为什么这种方法是有效的?

该算法并非暴力地枚举所有可能的容器(那样的时间复杂度会是 O(n^2)),而是通过一种贪心的策略,每次移动指针都朝着有可能增大面积的方向前进。 最终,它能够保证找到全局的最大面积。

使用双指针来界定容器的边界,并通过每次移动高度较小的指针的方式,贪心地寻找更大的容器面积,最终找到全局最大值。

详细解析

  • let left = 0;let right = height.length - 1; : 这两行初始化了两个指针,left 指针指向数组的开头,right 指针指向数组的结尾。 这两个指针用来定义当前容器的左右边界。

  • while (left < right) : 这是一个 while 循环,只要 left 指针还在 right 指针的左边,循环就会继续执行。 当 leftright 相遇时,说明已经遍历了所有可能的容器,循环结束。

  • const width = right - left; : 这行计算当前容器的宽度,即左右指针之间的距离。

  • const minHeight = Math.min(height[left], height[right]); : 这行计算当前容器的高度,即左右指针指向的高度的较小值。容器的高度由较短的线段决定,因为水只能填充到较短线段的高度。

  • const currentWater = width * minHeight; : 这行计算当前容器的容量,即宽度乘以高度。

  • maxWater = Math.max(maxWater, currentWater); : 这行更新 maxWater,如果当前容器的容量大于 maxWater,则将 maxWater 更新为当前容量。

  • if (height[left] < height[right]) { left++; } else { right--; } : 这是移动指针的关键部分。 总是移动高度较小的那个指针。 原因如下:

    • 如果移动较高的指针,容器的宽度会减小,而高度最多只能保持不变(最坏的情况),因此面积不可能增大。
    • 如果移动较低的指针,虽然宽度会减小,但高度有可能增加,从而有可能找到更大的面积。

实例与展示

三、结语

再见!

相关推荐
小O的算法实验室11 小时前
2026年IEEE TETCI,山区环境下基于双种群进化的协同无人机巡逻任务协同优化,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
生成论实验室11 小时前
《事件关系阴阳博弈动力学:识势应势之道》第二篇:阴阳博弈——认知的动力学基础
数据结构·人工智能·科技·神经网络·算法
We་ct12 小时前
深度剖析浏览器跨域问题
开发语言·前端·浏览器·跨域·cors·同源·浏览器跨域
风筝在晴天搁浅12 小时前
字节高频题 小于n的最大数
算法
LabVIEW开发12 小时前
LabVIEW水力机组空蚀在线监测
算法·labview·labview知识·labview功能·labview程序
AI科技星12 小时前
科幻艺术书本封面:《全域数学》第一部·数术本源 第三卷 代数原本(P95-141)完整五级目录【乖乖数学】
算法·机器学习·数学建模·数据挖掘·量子计算
风筝在晴天搁浅12 小时前
LeetCode 92.反转链表Ⅱ
算法·leetcode·链表
weisian15112 小时前
基础篇--概念原理-2-参数是什么?——从原理到实战,一篇讲透
面试·职场和发展·模型参数·7b和70b·参数=规则,不是原始数据
王老师青少年编程12 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【贪心与二分判定】:数列分段 Section II
c++·算法·贪心·csp·信奥赛·二分判定·数列分段 section ii
weixin_4277716112 小时前
前端调试隐藏元素
前端