代码训练(38)盛最多水的容器
Author: Once Day Date: 2025年6月22日
漫漫长路,才刚刚开始…
全系列文章可参考专栏: 十年代码训练_Once-Day的博客-优快云博客
参考文章:
1. 原题
给定一个长度为
n
的整数数组height
。有n
条垂线,第i
条线的两个端点是(i, 0)
和(i, height[i])
。找出其中的两条线,使得它们与
x
轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。
**说明:**你不能倾斜容器。
提示:
n == height.length
2 <= n <= 105
0 <= height[i] <= 104
示例 1:
输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例 2:
输入:height = [1,1]
输出:1
2. 分析
这道题目其实是一个非常经典的问题,在算法中称为“盛最多水的容器”。给定一个数组 height
,数组中的每个元素代表垂直线的高度,数组的索引表示垂直线的位置。我们需要找到两根线,这两根线与 x 轴形成的容器可以容纳最大量的水。
一个直观的方法是使用双重循环枚举所有可能的线对,计算它们构成的容器的容积,然后找出最大值。但这种方法的时间复杂度是 O(n^2),对于较大的 n 来说效率不高。
一个更高效的办法是使用双指针技术:
- 初始化两个指针,一个指向数组的开始(
left
),一个指向数组的结束(right
)。 - 计算当前两个指针指向的线构成的容器的容积,并更新最大容积。
- 移动两个指针中指向较矮线的那一个(因为容器的容积受到较矮的线的限制,希望找到可能更高的线以增加容积)。
- 重复步骤2和3,直到两个指针相遇。
以数组 height = [1, 8, 6, 2, 5, 4, 8, 3, 7]
为例:
- 初始化:
left = 0
,right = 8
,最大容积max_area = 0
- 计算容积:
min(height[left], height[right]) * (right - left) = min(1, 7) * (8 - 0) = 7
- 移动
left
指针(因为height[left] < height[right]
) - 这样的操作持续进行,直到
left
与right
相遇。
性能优化关键点:
- 时间复杂度: 双指针方法将时间复杂度降低到 O(n)。
- 空间复杂度: O(1),因为除了输入数组外没有使用额外的空间。
3. 代码实现
#include <stdio.h>
int maxArea(int* height, int heightSize) {
int left = 0, right = heightSize - 1;
int max_area = 0;
while (left < right) {
int width = right - left;
int h = height[left] < height[right] ? height[left] : height[right];
int current_area = width * h;
if (current_area > max_area) {
max_area = current_area;
}
if (height[left] < height[right]) {
left++;
} else {
right--;
}
}
return max_area;
}
int main() {
int height[] = {1, 8, 6, 2, 5, 4, 8, 3, 7};
int n = sizeof(height) / sizeof(height[0]);
int result = maxArea(height, n);
printf("最大储水量是: %d\n", result);
return 0;
}
4. 总结
这个问题考验了对双指针技术的理解和应用,是一个在面试中常见的问题。通过这种问题,可以提升对数组和指针操作的熟悉度,以及如何优化问题的解法以达到更高效的算法实现。在实际编程中,了解并应用各种算法和数据结构是非常重要的,可以通过类似问题的练习来加深理解和应用能力。