最大子数组和问题的变种——最多允许删除一个元素的最大子数组和
字数 1492 2025-11-14 01:27:27
最大子数组和问题的变种——最多允许删除一个元素的最大子数组和
我将为您详细讲解这个线性动态规划问题。这个问题是经典最大子数组和问题的有趣变种,增加了删除一个元素的灵活性。
问题描述
给定一个整数数组nums,我们需要找到具有最大和的连续子数组。与经典问题不同的是,这里我们允许从子数组中最多删除一个元素(也可以不删除)。要求返回这个最大和。
示例:
- 输入:[1, -2, 0, 3]
- 输出:4
- 解释:删除-2后,子数组[1, 0, 3]的和为4
解题思路分析
这个问题需要在经典最大子数组和问题的基础上进行扩展。我们需要考虑两种情况:
- 不删除任何元素的情况(经典最大子数组和)
- 删除一个元素的情况
详细解题步骤
步骤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:删除一个元素
这种情况有两种可能性:
- 删除当前元素:那么结果就是
dp_no_delete[i-1](因为当前元素被删除了) - 之前已经删除了某个元素:那么结果就是
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
这个问题的关键在于理解删除操作的两种可能性,并通过两个状态来分别跟踪这两种情况。