【每日一题】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. 接雨水:在数组中寻找形成容器的最大水量,运用双指针法可以减少时间复杂度。

总结

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

相关推荐
iFlyCai3 分钟前
Xcode警报“Ignoring duplicate libraries: ‘-lc++’” 警报
开发语言·c++
xiecoding.cn24 分钟前
Sublime Text使用教程(用Sublime Text编写C语言程序)
c语言·c++·青少年编程·编辑器·sublime text
Elendill1 小时前
【算法笔记】并查集详解
笔记·python·算法
oioihoii1 小时前
C++23新特性:显式对象形参与显式对象成员函数
开发语言·c++·c++23
埜玊1 小时前
this指针 和 类的继承
c++
BanyeBirth1 小时前
C++高精度算法(加、减、乘)
开发语言·c++·算法
houliabc1 小时前
C语言个人笔记
c语言·数据结构·笔记·算法
Allen Wurlitzer2 小时前
算法刷题记录——LeetCode篇(1.9) [第81~90题](持续更新)
算法·leetcode·职场和发展
@MrLiu2 小时前
# 深度学习中的优化算法详解
人工智能·深度学习·算法·优化器
小王努力学编程2 小时前
【Linux网络编程】UDP Echo Server的实现
linux·运维·服务器·网络·c++·学习·udp