最大子数组和问题的变种——最多允许删除一个元素的最大子数组和
字数 1492 2025-11-14 01:27:27

最大子数组和问题的变种——最多允许删除一个元素的最大子数组和

我将为您详细讲解这个线性动态规划问题。这个问题是经典最大子数组和问题的有趣变种,增加了删除一个元素的灵活性。

问题描述

给定一个整数数组nums,我们需要找到具有最大和的连续子数组。与经典问题不同的是,这里我们允许从子数组中最多删除一个元素(也可以不删除)。要求返回这个最大和。

示例:

  • 输入:[1, -2, 0, 3]
  • 输出:4
  • 解释:删除-2后,子数组[1, 0, 3]的和为4

解题思路分析

这个问题需要在经典最大子数组和问题的基础上进行扩展。我们需要考虑两种情况:

  1. 不删除任何元素的情况(经典最大子数组和)
  2. 删除一个元素的情况

详细解题步骤

步骤1:定义状态

我们使用两个动态规划数组:

  • dp_no_delete[i]:表示以第i个元素结尾,且没有删除任何元素的最大子数组和
  • dp_delete[i]:表示以第i个元素结尾,且已经删除过一个元素的最大子数组和

步骤2:状态转移方程

情况1:不删除任何元素

dp_no_delete[i] = max(nums[i], dp_no_delete[i-1] + nums[i])

这个与经典最大子数组和问题相同:要么从当前元素重新开始,要么延续前面的子数组。

情况2:删除一个元素
这种情况有两种可能性:

  1. 删除当前元素:那么结果就是dp_no_delete[i-1](因为当前元素被删除了)
  2. 之前已经删除了某个元素:那么结果就是dp_delete[i-1] + nums[i]

因此:

dp_delete[i] = max(dp_no_delete[i-1], dp_delete[i-1] + nums[i])

步骤3:初始条件

dp_no_delete[0] = nums[0]
dp_delete[0] = 0  // 第一个元素无法删除(因为至少要保留一个元素)

步骤4:最终结果

最终答案是所有dp_no_delete[i]dp_delete[i]中的最大值。

完整算法实现

def maximumSum(arr):
    n = len(arr)
    if n == 0:
        return 0
    if n == 1:
        return arr[0]
    
    dp_no_delete = [0] * n
    dp_delete = [0] * n
    
    # 初始化
    dp_no_delete[0] = arr[0]
    dp_delete[0] = 0  # 第一个元素无法删除
    
    result = max(dp_no_delete[0], dp_delete[0])
    
    for i in range(1, n):
        # 不删除任何元素的情况
        dp_no_delete[i] = max(arr[i], dp_no_delete[i-1] + arr[i])
        
        # 删除一个元素的情况
        # 可能性1:删除当前元素,那么结果就是前一个位置不删除的最大和
        # 可能性2:之前已经删除了某个元素,那么结果就是前一个位置删除的最大和加上当前元素
        dp_delete[i] = max(dp_no_delete[i-1], dp_delete[i-1] + arr[i])
        
        result = max(result, dp_no_delete[i], dp_delete[i])
    
    return result

示例演示

让我们通过一个例子来理解算法执行过程:

输入数组:[1, -2, 0, 3]

初始化:

  • i=0: dp_no_delete[0] = 1, dp_delete[0] = 0, result = 1

迭代过程:

  • i=1:

    • dp_no_delete[1] = max(-2, 1 + (-2)) = max(-2, -1) = -1
    • dp_delete[1] = max(dp_no_delete[0], dp_delete[0] + (-2)) = max(1, 0 + (-2)) = max(1, -2) = 1
    • result = max(1, -1, 1) = 1
  • i=2:

    • dp_no_delete[2] = max(0, -1 + 0) = max(0, -1) = 0
    • dp_delete[2] = max(dp_no_delete[1], dp_delete[1] + 0) = max(-1, 1 + 0) = max(-1, 1) = 1
    • result = max(1, 0, 1) = 1
  • i=3:

    • dp_no_delete[3] = max(3, 0 + 3) = max(3, 3) = 3
    • dp_delete[3] = max(dp_no_delete[2], dp_delete[2] + 3) = max(0, 1 + 3) = max(0, 4) = 4
    • result = max(1, 3, 4) = 4

最终结果为4,对应删除-2后的子数组[1, 0, 3]。

算法分析

时间复杂度: O(n),只需要遍历数组一次
空间复杂度: O(n),使用两个长度为n的数组

可以通过使用变量代替数组来优化空间复杂度到O(1):

def maximumSum_optimized(arr):
    if not arr:
        return 0
    
    n = len(arr)
    if n == 1:
        return arr[0]
    
    no_delete = arr[0]
    delete_one = 0
    result = arr[0]
    
    for i in range(1, n):
        # 注意顺序:先计算delete_one,因为它依赖于前一个no_delete
        new_delete = max(no_delete, delete_one + arr[i])
        new_no_delete = max(arr[i], no_delete + arr[i])
        
        no_delete, delete_one = new_no_delete, new_delete
        result = max(result, no_delete, delete_one)
    
    return result

这个问题的关键在于理解删除操作的两种可能性,并通过两个状态来分别跟踪这两种情况。

最大子数组和问题的变种——最多允许删除一个元素的最大子数组和 我将为您详细讲解这个线性动态规划问题。这个问题是经典最大子数组和问题的有趣变种,增加了删除一个元素的灵活性。 问题描述 给定一个整数数组nums,我们需要找到具有最大和的连续子数组。与经典问题不同的是,这里我们允许从子数组中最多删除一个元素(也可以不删除)。要求返回这个最大和。 示例: 输入:[ 1, -2, 0, 3 ] 输出:4 解释:删除-2后,子数组[ 1, 0, 3 ]的和为4 解题思路分析 这个问题需要在经典最大子数组和问题的基础上进行扩展。我们需要考虑两种情况: 不删除任何元素的情况(经典最大子数组和) 删除一个元素的情况 详细解题步骤 步骤1:定义状态 我们使用两个动态规划数组: dp_no_delete[i] :表示以第i个元素结尾,且没有删除任何元素的最大子数组和 dp_delete[i] :表示以第i个元素结尾,且已经删除过一个元素的最大子数组和 步骤2:状态转移方程 情况1:不删除任何元素 这个与经典最大子数组和问题相同:要么从当前元素重新开始,要么延续前面的子数组。 情况2:删除一个元素 这种情况有两种可能性: 删除当前元素:那么结果就是 dp_no_delete[i-1] (因为当前元素被删除了) 之前已经删除了某个元素:那么结果就是 dp_delete[i-1] + nums[i] 因此: 步骤3:初始条件 步骤4:最终结果 最终答案是所有 dp_no_delete[i] 和 dp_delete[i] 中的最大值。 完整算法实现 示例演示 让我们通过一个例子来理解算法执行过程: 输入数组:[ 1, -2, 0, 3 ] 初始化: i=0: dp_ no_ delete[ 0] = 1, dp_ delete[ 0 ] = 0, result = 1 迭代过程: i=1: dp_ no_ delete[ 1 ] = max(-2, 1 + (-2)) = max(-2, -1) = -1 dp_ delete[ 1] = max(dp_ no_ delete[ 0], dp_ delete[ 0 ] + (-2)) = max(1, 0 + (-2)) = max(1, -2) = 1 result = max(1, -1, 1) = 1 i=2: dp_ no_ delete[ 2 ] = max(0, -1 + 0) = max(0, -1) = 0 dp_ delete[ 2] = max(dp_ no_ delete[ 1], dp_ delete[ 1 ] + 0) = max(-1, 1 + 0) = max(-1, 1) = 1 result = max(1, 0, 1) = 1 i=3: dp_ no_ delete[ 3 ] = max(3, 0 + 3) = max(3, 3) = 3 dp_ delete[ 3] = max(dp_ no_ delete[ 2], dp_ delete[ 2 ] + 3) = max(0, 1 + 3) = max(0, 4) = 4 result = max(1, 3, 4) = 4 最终结果为4,对应删除-2后的子数组[ 1, 0, 3 ]。 算法分析 时间复杂度: O(n),只需要遍历数组一次 空间复杂度: O(n),使用两个长度为n的数组 可以通过使用变量代替数组来优化空间复杂度到O(1): 这个问题的关键在于理解删除操作的两种可能性,并通过两个状态来分别跟踪这两种情况。