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

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

给定一个长度为 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--; } : 这是移动指针的关键部分。 总是移动高度较小的那个指针。 原因如下:

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

实例与展示

三、结语

再见!

相关推荐
getapi几秒前
flutter app实现分辨率自适应的图片资源加载
前端·javascript·flutter
东雁西飞24 分钟前
MATLAB 控制系统设计与仿真 - 39
开发语言·算法·matlab·自动化·工业机器人
—Qeyser29 分钟前
用 Deepseek 写的html油耗计算器
前端·javascript·css·html·css3·deepseek
萌萌哒草头将军32 分钟前
VsCode Colipot 🚗 + MCP Tools ✈️ = 让你的编程体验直接起飞 🚀🚀🚀
前端·visual studio code·mcp
萌萌哒草头将军38 分钟前
🚀🚀🚀MCP SDK 快速接入 DeepSeek 并添加工具!万万没想到MCP这么简单好用!
前端·javascript·mcp
SuperCandyXu39 分钟前
leetcode0113. 路径总和 II - medium
数据结构·c++·算法·leetcode
硬匠的博客1 小时前
C++继承与派生
数据结构·算法
拉不动的猪1 小时前
简单回顾下useMemo
前端·javascript·面试
rigidwill6661 小时前
LeetCode hot 100—单词搜索
数据结构·c++·算法·leetcode·职场和发展
描绘一抹色1 小时前
力扣-hot100(无重复字符的最长子串)
数据结构·算法·leetcode