【每日一题】LeetCode - 盛最多水的容器

给定一个长度为 n 的整数数组 height。有 n 条垂线,第 i 条线的两个端点是 (i, 0)(i, height[i])。要求找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

输入示例

cpp 复制代码
height = [1,8,6,2,5,4,8,3,7]

输出

cpp 复制代码
49

解释

在此情况下,最大水容量为 49,选择的两个端点分别在位置 1 和位置 8。

解题思路

这个问题的关键在于找到一对垂线,使得它们之间的距离乘以两条线中较短的一条的高度值达到最大。我们可以使用以下两种算法进行求解。

暴力法

最直接的方法是遍历每一对垂线,计算其形成的容器容量,取其中的最大值。这种方法的时间复杂度较高,但能保证得到正确的结果。

代码实现:
cpp 复制代码
class Solution {
public:
    int maxArea(vector<int>& height) {
        int l = 0, ans = 0;
        for(int i = 0; i < height.size(); i++) {
            for(int k = i; k < height.size(); k++) {
                int m = min(height[i], height[k]);
                ans = max((k - i) * m, ans);
            }
        } 
        return ans;
    }
};
时间复杂度分析:

暴力法的时间复杂度为 O ( n 2 ) O(n^2) O(n2),因为我们需要遍历数组中的每一对垂线。空间复杂度为 O ( 1 ) O(1) O(1),仅使用了常量空间。

优缺点:

暴力法虽然简单直接,但在数据量较大时效率低下。适合数据量较小的情况。


双指针法

双指针法是一种优化算法,它使用左右两个指针从数组两端逐渐向中间移动。在每一步中,通过计算两个指针指向的垂线形成的容器面积,并与当前最大面积进行比较,保留较大的值。然后将较短的垂线的指针向中间移动,这样可以有效减少计算量。

我们使用两个指针从数组两端向中间逼近来寻找最大容积。由于面积由最短的边和两边之间的距离决定,因此我们可以使用以下策略来不断逼近最大面积:

  1. 初始化左指针 l 指向数组的最左端,右指针 r 指向数组的最右端。
  2. 计算以 lr 两条线组成的容器的面积 Area = (r - l) * min(height[l], height[r])
  3. 若当前面积比已有的最大面积大,则更新最大面积。
  4. 比较 height[l]height[r] 的高度:
    • height[l] < height[r],说明左边的线较短,为了可能找到更大的面积,我们将左指针右移一格 l++
    • 否则,右指针左移一格 r--
  5. 重复上述过程,直到左右指针相遇为止。
为什么这种方法有效?

因为若一对指针组成的容器容量较小,由于容量取决于 较短的边,所以只移动较短的那条边,可能才有机会得到更大的容积。而移动较长的那边对容积并没有帮助。

代码实现:
cpp 复制代码
class Solution {
public:
    int maxArea(vector<int>& height) {
        int l = 0, r = height.size() - 1, ans = 0;
        while (l < r) {
            ans = max(ans, (r - l) * min(height[r], height[l]));
            if (height[r] < height[l]) r--;
            else l++;
        }
        return ans; 
    }
};
代码解析
  1. lr 初始化为左右两端的指针。
  2. ans 用于存储最大面积,初始为 0。
  3. while(l < r):当左右指针相遇时停止迭代。
  4. 每次迭代中更新 ans 为当前最大面积。
  5. 比较 height[l]height[r],移动较短的一端的指针,直到 l >= r
时间复杂度分析:

双指针法的时间复杂度为 O ( n ) O(n) O(n),只需遍历一遍数组。空间复杂度为 O ( 1 ) O(1) O(1)。

优缺点:

双指针法效率更高,适用于大数据量的情况,能在不遍历所有组合的前提下找到最优解。

两种方法对比

方法 时间复杂度 空间复杂度 优势 劣势
暴力法 O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1) 实现简单,便于理解 数据量大时效率低下
双指针法 O ( n ) O(n) O(n) O ( 1 ) O(1) O(1) 效率高,适用于大数据量 实现稍微复杂

拓展思路

这种双指针思想可以在很多数组问题中应用。例如:

  1. 三数之和:通过固定一个数,使用双指针法在剩余的子数组中寻找其他两个数,使得它们的和为目标值。
  2. 接雨水:在数组中寻找形成容器的最大水量,运用双指针法可以减少时间复杂度。

总结

这道题考查了对双指针的理解和应用。在理解基本逻辑的基础上,掌握双指针的移动策略,可以有效减少算法复杂度。双指针法是一种经典的数组优化方法,在处理类似问题时能有效提升效率。

相关推荐
我们的五年4 分钟前
【Linux课程学习】:进程描述---PCB(Process Control Block)
linux·运维·c++
张彦峰ZYF5 分钟前
投资策略规划最优决策分析
分布式·算法·金融
The_Ticker20 分钟前
CFD平台如何接入实时行情源
java·大数据·数据库·人工智能·算法·区块链·软件工程
程序猿阿伟20 分钟前
《C++ 实现区块链:区块时间戳的存储与验证机制解析》
开发语言·c++·区块链
Lenyiin1 小时前
02.06、回文链表
数据结构·leetcode·链表
爪哇学长1 小时前
双指针算法详解:原理、应用场景及代码示例
java·数据结构·算法
爱摸鱼的孔乙己1 小时前
【数据结构】链表(leetcode)
c语言·数据结构·c++·链表·csdn
Dola_Pan1 小时前
C语言:数组转换指针的时机
c语言·开发语言·算法
繁依Fanyi1 小时前
简易安卓句分器实现
java·服务器·开发语言·算法·eclipse
烦躁的大鼻嘎1 小时前
模拟算法实例讲解:从理论到实践的编程之旅
数据结构·c++·算法·leetcode