2023-06-27 1186. 删除一次得到子数组最大和

130 阅读2分钟

leetcode.cn/problems/ma…

使用动态规划解决问题。拍脑袋后,把问题中的状态定义成如下形式

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],只用两个变量存储,不需要创建数组记录整个过程。

这题不会做,看了题解定义的状态,才豁然开朗。。。

leetcode.cn/problems/ma…