盛最多水的容器

题目要求

给定一个长度为 n 的整数数组 height,该数组代表了 n 条垂直线段的高度,每条线段的两个端点分别是 (i, 0)(i, height[i])。任务是从这些线段中找出两条线,这两条线与 x 轴一起形成的容器可以存储最大量的水。

需要返回的是这个容器能够存储的水的最大量。注意,构成容器的线段必须是垂直于 x 轴的,也就是说,容器的边不能倾斜。

解题思路

这个问题可以通过双指针法来解决。初始时,我们可以将两个指针分别放在数组的开始和结束位置,这代表了容器的两边。容器的容量由两个指针之间的距离(容器的宽度)和两个指针中较短线段的高度(容器的高度)的乘积来决定。

解题步骤如下:

  1. 初始化两个指针:left 指针在数组的开始位置,right 指针在数组的结束位置。
  2. 初始化最大容量 max_area 为 0。
  3. 当 left 指针小于 right 指针时,执行以下步骤:
    • 计算当前 left 和 right 指针所指线段构成的容器的容量,计算方式为 min(height[left], height[right]) * (right - left)
    • 更新 max_area,如果当前计算的容量大于 max_area,则将其赋值给 max_area。
    • 移动指针以尝试找到更大的容量。由于容器的容量受限于较短的线段,我们应该移动较短的那个线段对应的指针。如果 height[left] < height[right],则移动 left 指针,否则移动 right 指针。
  4. 重复步骤 3,直到 left 指针不再小于 right 指针。
  5. 返回 max_area 作为结果。

这种方法的关键在于,我们总是尝试通过移动较短的线段来找到可能更高的线段,因为这是增加容器容量的唯一方式。容器的宽度随着指针的移动是单调递减的,所以我们需要通过提高高度来弥补宽度的减少,以此来找到可能的最大容量。

Golang 版本

package main

import "fmt"

func maxArea(height []int) int {
    left, right := 0, len(height)-1
    maxArea := 0

    for left < right {
        // Calculate the area with the current boundary
        width := right - left
        high := min(height[left], height[right])
        currentArea := width * high
        // Update maxArea if the current area is greater
        maxArea = max(maxArea, currentArea)

        // Move the shorter line to try and find a taller line
        if height[left] < height[right] {
            left++
        } else {
            right--
        }
    }

    return maxArea
}

// Helper function to find the minimum of two integers
func min(x, y int) int {
    if x < y {
        return x
    }
    return y
}

// Helper function to find the maximum of two integers
func max(x, y int) int {
    if x > y {
        return x
    }
    return y
}

func main() {
    // Example usage:
    height := []int{1,8,6,2,5,4,8,3,7}
    fmt.Println("The maximum amount of water that can be contained is:", maxArea(height))
}

这段代码定义了一个 maxArea 函数,它接受一个整数切片 height 作为参数,并返回一个整数,表示按照题目要求能够容纳的最大水量。主函数 main 提供了一个示例用法。

C++版本

#include <iostream>
#include <vector>
#include <algorithm>

int maxArea(std::vector<int>& height) {
    int left = 0, right = height.size() - 1;
    int maxArea = 0;

    while (left < right) {
        // Calculate the area with the current boundary
        int width = right - left;
        int high = std::min(height[left], height[right]);
        int currentArea = width * high;
        // Update maxArea if the current area is greater
        maxArea = std::max(maxArea, currentArea);

        // Move the shorter line to try and find a taller line
        if (height[left] < height[right]) {
            left++;
        } else {
            right--;
        }
    }

    return maxArea;
}

int main() {
    // Example usage:
    std::vector<int> height = {1,8,6,2,5,4,8,3,7};
    std::cout << "The maximum amount of water that can be contained is: " << maxArea(height) << std::endl;
    return 0;
}

这段代码定义了一个 maxArea 函数,它接受一个整数向量 height 作为参数,并返回一个整数,表示按照题目要求能够容纳的最大水量。main 函数提供了一个示例用法。

Python 版本

def max_area(height):
    left, right = 0, len(height) - 1
    max_area = 0

    while left < right:
        # Calculate the area with the current boundary
        width = right - left
        high = min(height[left], height[right])
        current_area = width * high
        # Update max_area if the current area is greater
        max_area = max(max_area, current_area)

        # Move the shorter line to try and find a taller line
        if height[left] < height[right]:
            left += 1
        else:
            right -= 1

    return max_area

# Example usage:
if __name__ == "__main__":
    height = [1, 8, 6, 2, 5, 4, 8, 3, 7]
    print("The maximum amount of water that can be contained is:", max_area(height))

这段代码定义了一个 max_area 函数,它接受一个整数列表 height 作为参数,并返回一个整数,表示按照题目要求能够容纳的最大水量。if __name__ == "__main__": 部分提供了一个示例用法。

Java 版本

public class Solution {
    public int maxArea(int[] height) {
        int left = 0, right = height.length - 1;
        int maxArea = 0;

        while (left < right) {
            // Calculate the area with the current boundary
            int width = right - left;
            int high = Math.min(height[left], height[right]);
            int currentArea = width * high;
            // Update maxArea if the current area is greater
            maxArea = Math.max(maxArea, currentArea);

            // Move the shorter line to try and find a taller line
            if (height[left] < height[right]) {
                left++;
            } else {
                right--;
            }
        }

        return maxArea;
    }

    public static void main(String[] args) {
        Solution solution = new Solution();
        int[] height = {1, 8, 6, 2, 5, 4, 8, 3, 7};
        System.out.println("The maximum amount of water that can be contained is: " + solution.maxArea(height));
    }
}

这段代码定义了一个名为 Solution 的类,其中包含了 maxArea 方法,该方法接受一个整数数组 height 作为参数,并返回一个整数,表示按照题目要求能够容纳的最大水量。main 方法提供了一个示例用法。

Rust 版本

fn max_area(height: Vec<i32>) -> i32 {
    let (mut left, mut right) = (0, height.len() - 1);
    let mut max_area = 0;

    while left < right {
        let width = (right - left) as i32;
        let high = std::cmp::min(height[left], height[right]);
        let current_area = width * high;
        max_area = std::cmp::max(max_area, current_area);

        if height[left] < height[right] {
            left += 1;
        } else {
            right -= 1;
        }
    }

    max_area
}

fn main() {
    let height = vec![1, 8, 6, 2, 5, 4, 8, 3, 7];
    println!("The maximum amount of water that can be contained is: {}", max_area(height));
}

这段代码定义了一个 max_area 函数,它接受一个整数向量 height 作为参数,并返回一个整数,表示按照题目要求能够容纳的最大水量。main 函数提供了一个示例用法。

总结

上述问题是一个经典的数组操作问题,通常称为“盛最多水的容器”。解决这个问题的关键在于使用双指针法。以下是解决这个问题的步骤:

  1. 初始化两个指针,一个在数组的开始位置(left),另一个在数组的结束位置(right)。
  2. 初始化一个变量来跟踪最大面积(maxArea)。
  3. 当左指针小于右指针时,执行以下操作:
    • 计算当前两个指针之间的宽度(right - left)。
    • 找出两个指针指向的高度中较小的一个。
    • 计算当前的面积(当前宽度 * 较小的高度)。
    • 如果当前面积大于之前记录的最大面积,则更新最大面积。
    • 移动较短的那个指针(如果左边的高度小于右边的高度,则移动左指针;否则,移动右指针)。
  4. 当左指针不再小于右指针时,结束循环。
  5. 返回记录的最大面积。

这个算法的时间复杂度是 O(n),因为每个元素只被访问一次。空间复杂度是 O(1),因为只使用了常数空间。

在不同的编程语言中,这个算法的实现细节可能略有不同,但核心逻辑是一致的。例如,在 Rust 中,数组的长度是通过 len() 方法获取的,而在 Python 中则是通过内置的 len() 函数。同样,最小值和最大值的函数在不同的语言中也有所不同(如 std::minstd::maxMath.minMath.max 等)。