使用动态规划解决问题。拍脑袋后,把问题中的状态定义成如下形式
dp[i][k]: 定义为数组以 arr[i] 结尾,同时删除 k 次,子数组最大的和
那么对于本题最多只能删除一次的场景,有如下的定义:
- dp[i][0]: 数组以arr[i] 结尾,删除 0 次后,子数组最大的和
- dp[i][1]: 数组以arr[i] 结尾,删除 1 次后,子数组最大的和
状态转移方程
当 i = 0 时:
- dp[0][0] = arr[0],就是第一个元素
- dp[0][1] = 0,没有意义,只是为了赋一个初始值。因为只有一个元素的子数组,不能进行删除元素的操作
当 i > 0 时:
dp[i][0] = max(dp[i - 1][0], 0) + arr[i]不执行删除元素的操作- 如果dp[i - 1][0] 是负数,不如直接让dp[i][0] = arr[i],这样可以获得最大值。
- 否则,就把arr[i] 加到 dp[i - 1][0] 上获得更大的和。
dp[i][1] = max(dp[i - 1][1] + arr[i], dp[i - 1][0])执行删除元素操作- 有两种情况,一种删除的元素在以 arr[i - 1] 结尾的数组的子数组中,这个时候要加上 arr[i],这就是 max函数 中的第一个参数
- 第二种情况是,要删除的元素是 arr[i],那么此时的和就是以 arr[i - 1] 结尾,并且没有执行删除元素的的数组的结果,这就是 max函数 中的第二个参数
class Solution {
public int maximumSum(int[] arr) {
// dp[i][k]: 定义为数组以 arr[i] 结尾,同时删除 k 次时,子数组最大的和
// dp[i][0]: 数组以arr[i] 结尾,删除 0 次后,子数组最大的和
// dp[i][1]: 数组以arr[i] 结尾,删除 1 次后,子数组最大的和
// 转移方程 i > 0
// dp[i][0] = max(dp[i - 1][0], 0) + arr[i]
// dp[i][1] = max(dp[i - 1][1] + arr[i], dp[i - 1][0]);
int[][] dp = new int[arr.length][2];
dp[0][0] = arr[0];
dp[0][1] = 0;
int ans = dp[0][0];
for (int i = 1; i < arr.length; ++i) {
dp[i][0] = Math.max(dp[i - 1][0], 0) + arr[i];
dp[i][1] = Math.max(dp[i - 1][1] + arr[i], dp[i - 1][0]);
int larger = Math.max(dp[i][0], dp[i][1]);
ans = Math.max(ans, larger);
}
return ans;
}
}
可以优化 dp[i][0],dp[i][1],只用两个变量存储,不需要创建数组记录整个过程。
这题不会做,看了题解定义的状态,才豁然开朗。。。