📅  最后修改于: 2023-12-03 15:10:35.423000             🧑  作者: Mango
给定一个整数数组,找到最大子序列总和,使得在所有可能的解决方案中,三个子序列都不连续。例如, [-2,1,-3,4,-1,2,1,-5,4] 的最大子序列总和为 6 (来自 subarrays [4,-1,2,1]),且没有连续三个子序列。
暴力枚举法是最简单但相对最慢的解决方法。对给定数组进行所有可能的子序列求和,遍历并对每个子序列进行检查。如果检测到三个连续子序列,则跳过该子序列。
时间复杂度:O(n^3)
使用动态规划,我们可以将时间复杂度降至O(n)。
定义 dp[i] 表示以 arr[i] 为结尾的最大子序列和(不能包括前面已经计算的连续三个子序列)。如果已知 dp[i-1],则可以得到 dp[i] 的解决方案。如果 dp[i-1] 是正数,则将其加入 dp[i]。否则,将 dp[i] 置为 arr[i]。根据 dp[i] 更新最大值。
时间复杂度:O(n)
def maxSubArray(arr):
n = len(arr)
dp = [0] * n
dp[0] = arr[0]
dp2 = [0] * n # dp数组的备份数组
dp2[0] = arr[0]
res = arr[0] # 最大值
for i in range(1, n):
# dp[i]的值的计算
dp[i] = max(dp2[max(i-2, 0)], 0) + arr[i]
# 更新dp2
dp2[i] = max(dp2[i-1], dp[i])
# 更新最大值
res = max(res, dp[i])
return res
public int maxSubArray(int[] arr) {
int n = arr.length;
int[] dp = new int[n];
dp[0] = arr[0];
int[] dp2 = new int[n]; // dp数组的备份数组
dp2[0] = arr[0];
int res = arr[0]; // 最大值
for (int i = 1; i < n; i++) {
// dp[i]的值的计算
dp[i] = Math.max(dp2[Math.max(i-2, 0)], 0) + arr[i];
// 更新dp2
dp2[i] = Math.max(dp2[i-1], dp[i]);
// 更新最大值
res = Math.max(res, dp[i]);
}
return res;
}
int maxSubArray(vector<int>& arr) {
int n = arr.size();
int dp[n] = {0};
dp[0] = arr[0];
int dp2[n] = {0}; // dp数组的备份数组
dp2[0] = arr[0];
int res = arr[0]; // 最大值
for (int i = 1; i < n; i++) {
// dp[i]的值的计算
dp[i] = max(dp2[max(i-2, 0)], 0) + arr[i];
// 更新dp2
dp2[i] = max(dp2[i-1], dp[i]);
// 更新最大值
res = max(res, dp[i]);
}
return res;
}
本题可以通过动态规划的方法解决。定义一个 dp 数组来计算以每个元素为结尾的最大子序列和。为了避免连续的三个子序列,还需要一个 dp 数组的备份数组来记录不使用当前元素时(即 dp[i-2])的最大值。
代码中判断 dp[i-2] 的值是否小于 0,如果小于 0,则不能继续使用该元素,因为它会使其中一个子序列与前面的子序列相连。
由于动态规划只需遍历一次数组,因此时间复杂度为 O(n)。