算法题法算day5
lief盛最多水的容器
问题描述
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
✅ 说明:你不能倾斜容器。
示例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
提示:
n == height.length
2 <= n <= 105
0 <= height[i] <= 104
问题分析
这个问题是要找到两条垂直线,使得它们与x轴构成的容器能容纳最多的水。容器的容量由两个因素决定:
宽度:两条线之间的水平距离
高度:两条线中较短的那条线的高度
所以容量公式为:容量 = 距离 × min(左线高度, 右线高度)
为什么移动较短的线?
这是算法的关键点:
容器的容量由较短边的高度决定
每次移动指针,宽度都会减小
如果移动较长的边,容量只会更小(因为高度不会增加,宽度减小)
如果移动较短的边,有可能找到更高的边,从而增加容量
java版(双指针法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| public class ContainerWithMostWater { public static void main(String[] args) { // 测试用例1 int[] height1 = {1,8,6,2,5,4,8,3,7}; System.out.println("测试1结果: " + maxArea(height1)); // 应该输出49 // 测试用例2 int[] height2 = {1,1}; System.out.println("测试2结果: " + maxArea(height2)); // 应该输出1 } public static int maxArea(int[] height) { // 初始化左右指针,分别指向数组的首尾 int left = 0; int right = height.length - 1; // 记录最大面积 int maxArea = 0; // 当左右指针没有相遇时,继续循环 while (left < right) { // 计算当前两条线之间的宽度 int width = right - left; // 容器的高度取决于较短的那条线 int currentHeight = Math.min(height[left], height[right]); // 计算当前面积 int currentArea = width * currentHeight; // 更新最大面积 maxArea = Math.max(maxArea, currentArea); // 关键步骤:移动较短的那条线对应的指针 // 因为移动较长的线不会增加容量,而移动较短的线有可能找到更高的线 if (height[left] < height[right]) { left++; // 左指针右移 } else { right--; // 右指针左移 } } return maxArea; } }
|
✅ 说明:
- 时间复杂度:O(n) - 我们只需要遍历数组一次
- 空间复杂度:O(1) - 只使用了常数级别的额外空间
python版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| def maxArea(height): """ 计算容器能容纳的最大水量 使用双指针法,从数组的两端向中间移动 """ # 初始化左指针和右指针 left = 0 right = len(height) - 1 # 初始化最大面积 max_area = 0 # 当左指针小于右指针时循环 while left < right: # 计算当前左右指针构成的容器的面积 # 面积 = 宽度 * 高度,高度取左右指针中较小的那个 current_area = (right - left) * min(height[left], height[right]) # 更新最大面积 max_area = max(max_area, current_area) # 移动高度较小的指针,因为移动高度较大的指针不会增加面积 if height[left] < height[right]: left += 1 # 左指针右移 else: right -= 1 # 右指针左移 return max_area
# 测试代码 if __name__ == "__main__": # 示例1 height1 = [1,8,6,2,5,4,8,3,7] print(maxArea(height1)) # 输出: 49 # 示例2 height2 = [1,1] print(maxArea(height2)) # 输出: 1
|