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

57 阅读6分钟

我最近尝试了掘金的AI刷题,还挺有意思的,旁边会有一个小助手来帮助自己刷题。我给大家分享一下我最近刷的几道题的解析,还有我对ai助手的使用心得。

第一道例题,在最大矩形面积额这道题中,题目描述如下,### 问题描述

小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) 的最大值。 初步分析, - 对于每个可能的 ( k )(从 ( 1 ) 到 ( N )),遍历数组 ( h ) 来计算 ( R(k) )。 - 对于每个起始索引 ( i ),计算对应的 ( \min ) 值。 - 对于固定的 ( k ),我们需要找到 ( \min(h[i], h[i+1], \ldots, h[i+k-1]) )。这可以通过遍历这 ( k ) 个元素来实现。 - 在计算了所有的 ( R(k) ) 后,记录下每个 ( k ) 对应的最大值。 由于我们需要对每个 ( k ) 遍历 ( N ) 次,最坏情况下的时间复杂度为 ( O(N^2) )。如果 ( N ) 较大,这种方法可能会稍慢。 有以下写法, def solution(n, array): # Edit your code here max_area = 0 # 遍历每个可能的 k for k in range(1, n + 1): # 遍历所有长度为 k 的子数组 for i in range(n - k + 1): current_min = min(array[i:i + k]) # 找到当前子数组的最小值 area = k * current_min # 计算矩形面积 max_area = max(max_area, area) # 更新最大面积 return max_area if name == "main": # Add your test cases here

print(solution(5, [1, 2, 3, 4, 5]) == 9)

我们写完后可以向MarsCode请求进行代码的优化,优化一下代码

要优化当前的代码,我们可以考虑以下几个方面:

  1. 减少重复计算:当前代码在每次计算子数组的最小值时都会重新计算,这会导致重复计算,尤其是在 k 较大时。

  2. 使用更高效的数据结构:我们可以使用单调栈来维护一个递增的栈,这样可以快速找到每个元素作为最小值时的最大矩形面积。

优化思路

  1. 单调栈:我们可以使用单调栈来维护一个递增的栈,栈中存储的是数组元素的索引。当遇到一个比栈顶元素小的元素时,我们可以计算以栈顶元素为最小值的最大矩形面积。

  2. 遍历数组:遍历数组时,对于每个元素,我们检查它是否比栈顶元素小。如果是,则弹出栈顶元素并计算以该元素为最小值的最大矩形面积。

  3. 处理边界情况:在遍历结束后,栈中可能还有元素,这些元素也需要计算它们的最大矩形面积。

优化后的代码框架

def solution(n, array):
    # 初始化最大面积
    max_area = 0
    # 使用单调栈来维护一个递增的栈
    stack = []
    
    # 遍历数组
    for i in range(n):
        # 当栈不为空且当前元素小于栈顶元素时
        while stack and array[i] < array[stack[-1]]:
            # 弹出栈顶元素
            height = array[stack.pop()]
            # 计算宽度
            width = i if not stack else i - stack[-1] - 1
            # 计算面积并更新最大面积
            max_area = max(max_area, height * width)
        
        # 将当前元素的索引压入栈
        stack.append(i)
    
    # 处理栈中剩余的元素
    while stack:
        height = array[stack.pop()]
        width = n if not stack else n - stack[-1] - 1
        max_area = max(max_area, height * width)
    
    return max_area

if __name__ == "__main__":
    # Add your test cases here
    print(solution(5, [1, 2, 3, 4, 5]) == 9)

解释

  1. 单调栈:我们使用一个栈来维护一个递增的序列。栈中存储的是数组元素的索引。

  2. 遍历数组:在遍历数组时,如果当前元素比栈顶元素小,则弹出栈顶元素并计算以该元素为最小值的最大矩形面积。

  3. 处理边界情况:在遍历结束后,栈中可能还有元素,这些元素也需要计算它们的最大矩形面积。

通过这种方式,我们可以将时间复杂度从 O(n^2) 优化到 O(n),其中 n 是数组的长度。 如果我们觉得代码的效率还不够高,可以继续提示它进行优化, 当然可以进一步优化代码。虽然使用单调栈已经将时间复杂度优化到了 O(n),但我们还可以通过一些细节上的优化来提高代码的效率和可读性。

进一步优化思路

  1. 减少不必要的计算:在计算宽度时,我们可以直接使用当前索引和栈顶元素的索引来计算宽度,而不需要额外的判断。

  2. 简化代码逻辑:通过简化代码逻辑,可以使代码更易读和维护。

进一步优化后的代码

def solution(n, array):
    # 初始化最大面积
    max_area = 0
    # 使用单调栈来维护一个递增的栈
    stack = [-1]  # 初始化栈,栈底元素为 -1,方便计算宽度
    
    # 遍历数组
    for i in range(n):
        # 当栈不为空且当前元素小于栈顶元素时
        while stack[-1] != -1 and array[i] < array[stack[-1]]:
            # 弹出栈顶元素
            height = array[stack.pop()]
            # 计算宽度
            width = i - stack[-1] - 1
            # 计算面积并更新最大面积
            max_area = max(max_area, height * width)
        
        # 将当前元素的索引压入栈
        stack.append(i)
    
    # 处理栈中剩余的元素
    while stack[-1] != -1:
        height = array[stack.pop()]
        width = n - stack[-1] - 1
        max_area = max(max_area, height * width)
    
    return max_area

if __name__ == "__main__":
    # Add your test cases here
    print(solution(5, [1, 2, 3, 4, 5]) == 9)

解释

  1. 初始化栈:我们将栈初始化为 [-1],这样可以简化宽度的计算,因为 -1 可以作为边界条件。

  2. 遍历数组:在遍历数组时,如果当前元素比栈顶元素小,则弹出栈顶元素并计算以该元素为最小值的最大矩形面积。

  3. 处理边界情况:在遍历结束后,栈中可能还有元素,这些元素也需要计算它们的最大矩形面积。

通过这种方式,我们可以进一步简化代码逻辑,提高代码的可读性和效率。 最后完成提交,

Screenshot 2024-11-25 235143.png