如何修改DP算法获取数组非连续元素最大和的对应索引?
非连续元素最大和的索引追踪问题
问题背景与现有代码
我实现了一个DP算法计算数组非连续元素的最大和,但发现同类问题都没记录组成最大和的元素索引。原算法如下:
def maxSum(arr): sum = [0]*len(arr); sum_indices = [] for i in range(len(arr)): if i==0: sum[0] = arr[0]; elif(i==1): sum[1] = max(sum[0],arr[1]); else: sum[i] = max(sum[i-2]+arr[i],sum[i-1]); return sum[len(arr)-1];
我尝试修改代码以返回索引,但结果不符合预期:
def maxSum(A): n = len(A) M = [0]*len(A) M[0] = A[0] I = [None]*len(A) if A[0] > A[1]: M[1] = A[0] I[0] = True I[1] = False else: M[1] = A[1] I[0] = False I[1] = True for i in range(2, len(A)): if M[i-1] > M[i-2] + A[i]: M[i] = M[i-1] I[i] = False else: M[i] = M[i-2] + A[i] I[i] = True I[i-1] = False I[i-2] = True indices = [] print(I) for j in range(len(A)): if I[j] == True: indices.append(j) return indices
例如输入maxSum([1,2,3,8,9]),预期返回组成最大和的元素索引[1,3,4](对应元素2、8、9),但实际返回错误的索引列表。
错误原因
正向修改标记数组I时直接覆盖历史状态是核心问题:
- 当选择
M[i-2]+A[i]时,硬改I[i-1]为False、I[i-2]为True,但i-2位置的标记是否选中取决于更早的最优决策,不是当前i的选择能直接决定的。 - 这种篡改会导致后续循环的标记逻辑完全混乱,最终得到错误的索引集合。
正确解法:反向回溯索引
正确思路是先计算DP数组得到最大和,再从数组末尾反向回溯判断每个位置是否被选中,避免破坏历史状态:
实现步骤
- 计算标准DP数组,记录每个位置的最大非连续和;
- 从数组最后一位开始反向遍历:
- 若当前位置
i的最大和等于dp[i-2]+arr[i],说明当前元素被选中,加入索引列表后跳转到i-2; - 若等于
dp[i-1],说明未选中当前元素,跳转到i-1; - 处理边界情况(数组长度为1或2);
- 若当前位置
- 反转索引列表得到正序结果。
代码实现
def max_sum_with_indices(arr): n = len(arr) if n == 0: return [] if n == 1: return [0] # 计算DP数组 dp = [0] * n dp[0] = arr[0] dp[1] = max(arr[0], arr[1]) for i in range(2, n): dp[i] = max(dp[i-1], dp[i-2] + arr[i]) # 反向回溯索引 indices = [] i = n - 1 while i >= 0: if i == 0: indices.append(i) break if i == 1: indices.append(1 if dp[1] == arr[1] else 0) break if dp[i] == dp[i-2] + arr[i]: indices.append(i) i -= 2 else: i -= 1 # 反转得到正序索引 return indices[::-1]
测试验证
输入max_sum_with_indices([1,2,3,8,9]),返回[1,3,4],对应元素和为2+8+9=19,是正确的最大非连续和索引。
额外优化
该逻辑支持含负数的数组:当元素为负数时,DP数组会自动选择不选该元素(继承前一位的最大和)。例如输入[-2,1,3,-4,5],返回索引[1,4],对应元素和为6,是最优解。
内容的提问来源于stack exchange,提问作者SeamusF11
相关产品推荐
相关产品推荐

