🔍 登录 注册

盛最多水的容器

大 大苹果 2024-08-06 algorithm 👁 19 ⏱ 6min

给定一个长度为 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

解法一:

/**
 * @param {number[]} height
 * @return {number}
 */
var maxArea = function(height) {
    if (!height || height.length < 2) {
        return 0;
    }
    let max = 0;
    let res = 0;
    for (let i = 0; i < (height.length - 1); i++) {
        for (let j = i + 1; j < height.length; j++) {
            if (height[i] < height[j]) {
                res = height[i] * (j - i);
            } else {
                res = height[j] * (j - i);
            }
            if (res > max) {
                max = res;
            }
        }
    }
    return max;
};

耗时久,性能差


这个问题是著名的“盛水最多的容器”问题,可以通过双指针法来高效地解决。该算法的关键在于逐步缩小范围,同时记录能够容纳的最大水量。

解决方案概述

给定一个整数数组 height,我们需要找到两个索引 i 和 j(其中 i < j),使得 min(height[i], height[j]) * (j - i) 的值最大。这就是容器的最大水容量。

算法步骤

  1. 初始化双指针:

    • 设置两个指针,左指针 left 初始化为数组的起始位置 0,右指针 right 初始化为数组的终止位置 n-1,其中 n 是数组的长度。

  2. 计算当前水容量:

    • 在每一步中,计算由 left 和 right 指针所确定的容器的水容量:min(height[left], height[right]) * (right - left)。

    • 如果这个容量比目前记录的最大容量要大,就更新最大容量。

  3. 移动指针:

    • 由于水容量受限于短板(较短的那一边),我们选择移动高度较小的一端指针(即 height[left] 和 height[right] 中较小的那一个)来尝试寻找更长的高度。

    • 如果 height[left] < height[right],就把 left 指针右移(left++),否则就把 right 指针左移(right--)。

  4. 重复步骤2和步骤3,直到两个指针相遇。

  5. 输出结果:

    • 当两个指针相遇时,已经找到了最大水容量,输出这个最大值。

代码实现

def maxArea(height):
    # 初始化双指针
    left, right = 0, len(height) - 1
    max_water = 0
  
    while left < right:        # 计算当前容器的水容量
        current_water = min(height[left], height[right]) * (right - left)      
        # 更新最大水容量
        max_water = max(max_water, current_water)      
        # 移动指针
        if height[left] < height[right]:
            left += 1
        else:
            right -= 1
  
    return max_water# 示例测试heights = [1,8,6,2,5,4,8,3,7]print(maxArea(heights))  # 输出: 49

复杂度分析

  • 时间复杂度:O(n),其中 n 是数组的长度。每个元素最多被访问一次。

  • 空间复杂度:O(1),只使用了常量级别的额外空间。

示例

对于 heights = [1,8,6,2,5,4,8,3,7],上述代码将输出 49。这对应于垂线索引 1 和 8,它们之间的距离是 7,较短的垂线高度是 7,因此水容量是 7 * 7 = 49。

这个算法通过聪明地选择指针移动来高效地找到最优解,并且避免了冗余计算。


读完了?给作者一点支持

本文采用 CC BY 4.0 协议转载 · © 大苹果

评论(0)

登录 后参与评论。

  • 还没有评论,来抢沙发。

🔗 相关文章

动态规划从入门到进阶:状态设计与空间优化的完整方法论

从暴力递归到记忆化与递推,覆盖背包、区间、状态压缩等模型,给出动态规划状态设计与空间优化的完整方法论。

21 天前👍 0

Go 排序算法实战:从冒泡到 TimSort 的复杂度与工程取舍

用 Go 实现九种经典排序,剖析复杂度、稳定性与适用场景,并拆解标准库 sort 背后的 introsort 工程取舍。

21 天前👍 0

RabbitMQ 标准队列

RabbitMQ 标准队列(Classic Queue)是消息传递系统中最基本的队列类型,消息按先进先出(FIFO)的顺序存储和传递。以下是标准队列的常见应用场景和详细说明: ### 1. **任务队列(Task Queue)** - **场景描述**:在后台处理任务时,如图像处理、视频转码、数据分析等,需要将任务分配给多个工作节点进行处理,避免阻塞主应用。 - **应用说明**:在任务队列中,每个任务都会被推送到 RabbitMQ 的标准队列中,多个消费者从队列中获取任务并处理,任务处理完毕后删除队列中的消息。 - **举例**: - **应用**:电商网站后台处理订单数据,如生成发货单、发送确认邮件等。这些任务可以异步处理,以提高系统的响应速度。 - **代码示例(Node.js)**: ```javascript // 生产者:将任务添加到队列 const amqp = require('amqplib/callback_api'); amqp.connect('amqp://localhost', func

2024/8/11👍 0