寻找子数组和的最大值问题| 豆包MarsCode AI 刷题

60 阅读4分钟

问题描述

小U手上有一个整数数组,他想知道如果从数组中删除任意一个元素后,能得到的长度 为k的子数组和的最大值。你能帮小U计算出这个结果吗?如果数组恰好为k个元素 那么不进行删除操作。

题目难度:中

核心问题

这道题的核心在于如何高效地计算出所有可能的子数组和,并从中找出最大的那个。对于长度为n的数组来说,如果我们直接枚举所有可能的子数组并计算其和,虽然能够解决问题,但效率上会大打折扣,尤其是当n非常大的时候。因此,我们需要一种更加聪明的方法来优化这一过程。

解题思路

在提供的代码中,我们首先处理了一个特殊情况:如果数组的长度正好等于k,那么我们就无需删除任何元素,直接返回整个数组的和即可。这是因为在没有多余元素的情况下,整个数组本身就是我们要找的那个最优的子数组了。

接下来,为了找到删除一个元素后的最大子数组和,我们遍历数组中的每一个位置,尝试删除该位置上的元素,然后计算剩余部分中长度为k的子数组的和。这里有个小技巧,我们并不是真的删除元素,而是计算包含该元素在内的长度为k+1的子数组的和,再减去这个子数组中的最小值,这样就能得到删除该最小值后的新子数组和了。

最后,我们只需要从这些计算出来的子数组和中挑选出最大的那一个,就完成了任务。

主要逻辑

特殊情况: 如果数组的长度正好等于k,那么我们就不需要删除任何元素,直接返回整个数组的和即可。

接下来,我们需要考虑如何在删除一个元素后,找到长度为k的子数组和的最大值。为了实现这一点,我们可以采用以下步骤:

  1. 初始化一个列表 subarray_sums 来存储所有可能的子数组和。
  2. 遍历数组,尝试删除每个位置上的元素。具体来说,我们遍历数组的每一个位置 i,从0到 n - k(这里的 n 是数组的长度)。
  3. 计算子数组和:对于每个位置 i,我们计算从 i 开始的长度为 k+1 的子数组的和。为什么是 k+1 呢?因为我们要模拟删除一个元素的效果,所以计算的子数组长度比最终需要的子数组长度多1。
  4. 减去最小值:从上述子数组和中减去该子数组中的最小值,这样就能得到删除该最小值后的新子数组和。
  5. 存储结果:将计算得到的新子数组和存储到 subarray_sums 列表中。
  6. 返回最大值:最后,从 subarray_sums 列表中找到并返回最大的那个子数组和。

代码实现

以下是代码实现,详细注释解释了每个步骤:

def solution(n, k, nums): 
    # 如果数组长度正好等于k,不需要删除任何元素 
    if len(nums) == k: 
        return sum(nums) 
        
    subarray_sums = [] 
    # 遍历数组,尝试删除每个位置上的元素 
    for i in range(n - k): 
        # 计算包含当前位置在内的长度为k+1的子数组的和,然后减去其中的最小值 
        subarray_sums.append(sum(nums[i:i+k+1]) - min(nums[i:i+k+1])) 
        
    # 返回计算结果中的最大值 
    return max(subarray_sums)

测试案例

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

复杂度分析

  • 时间复杂度

    • 特殊情况处理(数组长度等于k)的时间复杂度是O(n),因为需要计算整个数组的和。
    • 主要循环的时间复杂度是O((n-k) * k),因为对于每个起始位置i,我们需要计算长度为k+1的子数组的和O(k),并找到其中的最小值O(k)。总的时间复杂度为O(n * k)。
  • 空间复杂度

    • 存储子数组和的空间复杂度是O(n-k),因为我们最多需要存储n-k个子数组和。
    • 其他变量占用的空间是常数级别的,所以总体空间复杂度为O(n-k)。