“青训营X豆包MarsCode 技术训练营第一课 | 豆包MarsCode AI 刷题

30 阅读4分钟

问题描述

小S最近在分析一个数组 h1,h2,...,hNh1​,h2​,...,hN​,数组的每个元素代表某种高度。小S对这些高度感兴趣的是,当我们选取任意 kk 个相邻元素时,如何计算它们所能形成的最大矩形面积。

对于 kk 个相邻的元素,我们定义其矩形的最大面积为:

R(k)=k×min(h[i],h[i+1],...,h[i+k−1])R(k)=k×min(h[i],h[i+1],...,h[i+k−1])

即,R(k)R(k) 的值为这 kk 个相邻元素中的最小值乘以 kk。现在,小S希望你能帮他找出对于任意 kk,R(k)R(k) 的最大值。


测试样例

样例1:

输入:n = 5, array = [1, 2, 3, 4, 5]
输出:9

样例2:

输入:n = 6, array = [5, 4, 3, 2, 1, 6]
输出:9

样例3:

输入:n = 4, array = [4, 4, 4, 4]
输出:16

问题分析

给定一个包含 nn 个整数的数组,要求我们对于任意长度为 kk 的相邻子数组,计算它们所能形成的最大矩形面积。面积计算的规则是:对于长度为 kk 的子数组,矩形的最大面积为 k×min⁡(h[i],h[i+1],…,h[i+k−1])k×min(h[i],h[i+1],…,h[i+k−1]),其中 min⁡min 表示该子数组的最小值。

解题思路

我们可以通过滑动窗口的方式,计算每个可能的长度 kk 所对应的最大矩形面积。具体来说,对于每个长度 kk 的子数组,我们可以找到该子数组的最小值,然后计算面积。

步骤

  1. 遍历所有可能的子数组长度:从 k=1k=1 到 k=nk=n,我们依次计算每个长度为 kk 的子数组的最大矩形面积。
  2. 计算每个子数组的最小值:对于给定的 kk,我们遍历数组的每个长度为 kk 的子数组,计算其最小值,并使用公式 k×min⁡(h[i],h[i+1],…,h[i+k−1])k×min(h[i],h[i+1],…,h[i+k−1]) 计算矩形面积。
  3. 优化:直接计算每个子数组的最小值可能比较慢(每次都要遍历 kk 个元素)。我们可以利用滑动窗口技巧,快速找到每个子数组的最小值,减少时间复杂度。

滑动窗口技巧

对于长度为 kk 的滑动窗口,我们可以维护一个单调队列来存储当前窗口的最小值。在每一时刻,我们只需要通过队列中的最小值来计算面积。

具体实现

pythonCopy Code
from collections import deque

def max_rectangle_area(n, array):
    # 计算每个可能的k值对应的最大矩形面积
    max_area = 0
    
    # 遍历所有可能的子数组长度k
    for k in range(1, n + 1):
        # 使用单调队列找出每个长度为k的子数组的最小值
        deq = deque()
        
        # 初始化队列,遍历前k个元素,计算第一个窗口的最小值
        for i in range(k):
            while deq and array[deq[-1]] >= array[i]:
                deq.pop()
            deq.append(i)
        
        # 计算第一个窗口的面积
        max_area = max(max_area, k * array[deq[0]])
        
        # 继续滑动窗口
        for i in range(k, n):
            # 移除队列中已经不在窗口范围内的元素
            while deq and deq[0] <= i - k:
                deq.popleft()
            
            # 向队列添加当前元素
            while deq and array[deq[-1]] >= array[i]:
                deq.pop()
            deq.append(i)
            
            # 计算当前窗口的最小值对应的矩形面积
            max_area = max(max_area, k * array[deq[0]])
    
    return max_area

# 测试样例
print(max_rectangle_area(5, [1, 2, 3, 4, 5]))  # 输出:9
print(max_rectangle_area(6, [5, 4, 3, 2, 1, 6]))  # 输出:9
print(max_rectangle_area(4, [4, 4, 4, 4]))  # 输出:16

解释

  1. 滑动窗口和单调队列

    • 使用队列维护当前窗口的最小值:队列中的元素按从小到大的顺序排列,队列的头部始终保存当前窗口的最小值。
    • 对于每一个 kk,我们计算所有可能的子数组的面积,并通过队列在 O(1)O(1) 时间内获取当前窗口的最小值,从而计算最大面积。
  2. 遍历所有可能的 kk

    • 我们遍历从 k=1k=1 到 k=nk=n 的所有子数组长度,对于每一个 kk,我们使用滑动窗口技术计算所有窗口的面积。

时间复杂度

  • 对于每个 kk,我们维护一个滑动窗口,该窗口会遍历数组一次,时间复杂度是 O(n)O(n)。
  • 总的时间复杂度为 O(n2)O(n2),因为我们需要计算所有从 k=1k=1 到 k=nk=n 的情况。

测试结果

  • 样例 1:输入 [1, 2, 3, 4, 5],最大矩形面积为 9。
  • 样例 2:输入 [5, 4, 3, 2, 1, 6],最大矩形面积为 9。
  • 样例 3:输入 [4, 4, 4, 4],最大矩形面积为 16。

此解法能够正确计算给定数组的所有可能的矩形面积,并返回最大值。