一、Problem
给你一个整数数组,返回它的某个 非空 子数组(连续元素)在执行一次可选的删除操作后,所能得到的最大元素总和。
换句话说,你可以从原数组中选出一个子数组,并可以决定要不要从中删除一个元素(只能删一次哦),(删除后)子数组中至少应当有一个元素,然后该子数组(剩下)的元素总和是所有子数组之中最大的。
注意,删除一个元素后,子数组 不能为空。
输入:arr = [1,-2,0,3]
输出:4
解释:我们可以选出 [1, -2, 0, 3],然后删掉 -2,这样得到 [1, 0, 3],和最大。
输入:arr = [1,-2,-2,3]
输出:3
解释:我们直接选出 [3],这就是最大和。
二、Solution
方法一:dp
- 定义状态:
- 表示以 结尾且没删过元素的子数组最大总和
- 表示以 结尾且删除过元素的子数组最大总和
- 思考初始化:
- 思考状态转移方程:
- 要么接着前一段,要么新开一段。
- 要么接着前一段;要么删除 就此断开。
- 思考输出:
class Solution {
public int maximumSum(int[] a) {
int n = a.length, INF = (int) -2e5, max = a[0], f[][] = new int[n][2];
f[0][0] = a[0];
f[0][1] = 0;
for (int i = 1; i < n; i++) {
f[i][0] = Math.max(a[i], f[i-1][0] + a[i]);
f[i][1] = Math.max(f[i-1][0], f[i-1][1] + a[i]);
max = Math.max(max, Math.max(f[i][0], f[i][1]));
}
return max;
}
}
复杂度分析
- 时间复杂度: ,
- 空间复杂度: ,
方法二:空间压缩
可以进行空间压缩,因为 f[i][0] 和 f[i][1] 只与前前一个状态有关
class Solution {
public int maximumSum(int[] a) {
int n = a.length, max = a[0];
int fi_0 = a[0], fi_1 = 0;
for (int i = 1; i < n; i++) {
int pre_fi_0 = fi_0;
fi_0 = Math.max(fi_0 + a[i], a[i]);
fi_1 = Math.max(fi_1 + a[i], pre_fi_0);
max = Math.max(max, Math.max(fi_0, fi_1));
}
return max;
}
}
复杂度分析
- 时间复杂度: ,
- 空间复杂度: ,