力扣每日一题1186. 删除一次得到子数组最大和【动态规划】

本题的核心在于对于每个元素,我们分别考虑保留和删除两种状态,并根据前面的状态转移来更新当前状态。最后,遍历所有元素,找到最大和即可。

状态定义

  • dp[i][0] 表示以第 i 个元素结尾且未删除元素的子数组的最大和。
  • dp[i][1] 表示以第 i 个元素结尾且删除了一个元素后的子数组的最大和。

状态转移方程

dp[i][0]

这是比较容易理解的部分。对于 dp[i][0],我们只需要考虑当前元素是否能使前面的子数组和变得更大:

dp[i][0]=max(dp[i−1][0],0)+arr[i]

这里的 max(dp[i-1][0], 0) 意味着:

  • 如果 dp[i-1][0] 是正的,加上当前元素 arr[i] 可以让子数组和变大。

  • 如果 dp[i-1][0] 是负的,我们不需要前面的子数组,直接从 arr[i] 开始一个新的子数组。

dp[i][1]

对于 dp[i][1],我们需要考虑是否删除一个元素,具体分为以下两种情况:

  1. arr[i] 是正的。

  2. arr[i] 是负的。

arr[i] 是正的:

如果当前元素是正的,我们可以选择将它加到之前的子数组上,因为这样肯定能使子数组和变大。这里需要考虑的是:

  • 前面的子数组是否已经删除过一个元素 (dp[i-1][1]),如果是且 dp[i-1][1] 是正的,则可以加上当前元素。

  • 如果 dp[i-1][1] 不是正的,我们就可以看作从 i-1 开始新起一个子数组(即第 i-1 个元素是被删除的那个)。

公式为:dp[i][ 1]=max(dp[i−1][1]+arr[i],dp[i−1][0])

arr[i] 是负的:

对于负数,我们有两种选择:

  1. 删除当前的负数 arr[i],接上前面的子数组,这样最大和就是 dp[i-1][0]

  2. 不删除当前的负数,而是把它加到已经删除过一个元素的子数组上(即 dp[i-1][1]),这时最大和是 dp[i-1][1] + arr[i]

公式为: ·dp[i][1]=max(dp[i−1][0],dp[i−1][1]+arr[i])

代码实现

public class Solution {
    public int maximumSum(int[] arr) {
        int n = arr.length;
        int[][] dp = new int[n][2];

        dp[0][0] = arr[0];
        dp[0][1] = 0;  // 刚开始没有删除元素,删除后至少应保留一个元素

        int maxSum = arr[0];

        for (int i = 1; i < n; 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]);

            // 更新最大和
            maxSum = Math.max(maxSum, Math.max(dp[i][0], dp[i][1]));
        }

        return maxSum;
    }

    public static void main(String[] args) {
        Solution solution = new Solution();
        int[] arr1 = {1, -2, 0, 3};
        int[] arr2 = {1, -2, -2, 3};
        int[] arr3 = {-1, -1, -1, -1};
        
        System.out.println(solution.maximumSum(arr1)); // 4
        System.out.println(solution.maximumSum(arr2)); // 3
        System.out.println(solution.maximumSum(arr3)); // -1
    }
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值