1746. 经过一次操作后的最大子数组和

1746. 经过一次操作后的最大子数组和

你有一个整数数组 nums。你只能将一个元素 nums[i] 替换为 nums[i] * nums[i]

返回替换后的最大子数组和。

示例 1:

输入:nums = [2,-1,-4,-3]
输出:17
解释:你可以把-4替换为16(-4*(-4)),使nums = [2,-1,16,-3]. 现在,最大子数组和为 2 + -1 + 16 = 17.

示例 2:

输入:nums = [1,-1,1,1,-1,-1,1]
输出:4
解释:你可以把第一个-1替换为1,使 nums = [1,1,1,1,-1,-1,1]. 现在,最大子数组和为 1 + 1 + 1 + 1 = 4.

解法一:经典 DP

思想

状态表示,操作即 nums[i] 替换为 nums[i] * nums[i]

  • f ( i , 0 ) f(i,0) f(i,0),以第 i i i 个数字为结尾,没有使用操作,最大子数组和
  • f ( i , 1 ) f(i,1) f(i,1),以第 i i i 个数字为结尾,已经使用操作,最大子数组和

此处 i i i 1 1 1 开始,题中 n u m s nums nums 的下标由 0 0 0 开始。也就是 f f f i i i 对应 n u m s nums nums i − 1 i − 1 i1

状态转移

  • i i i 个数字为结尾,没有使用操作,说明前 i − 1 i - 1 i1 个数字也没使用操作,所以由 f ( i − 1 , 0 ) f(i - 1,0) f(i1,0) 转移

  • i i i 个数字为结尾,使用了操作,则有两种转移方式

    • i − 1 i - 1 i1 个数字没使用操作,但第 i i i 个数字使用操作,所以由 f ( i − 1 , 0 ) f(i - 1,0) f(i1,0) 转移

    • i − 1 i - 1 i1 个数字已使用操作,所以由 f ( i − 1 , 1 ) f(i - 1,1) f(i1,1) 转移

状态计算

  • 不使用操作时,若前面最大值加上当前 n u m num num 是个负数,那干脆前面都不要子数组直接从 i i i 开始,
    f ( i , 0 ) = m a x { f ( i − 1 , 0 ) + n u m s ( i − 1 ) , 0 } f(i, 0) = max\{f(i - 1, 0) + nums(i-1), 0\} f(i,0)=max{f(i1,0)+nums(i1),0}
  • 使用操作时,由两种转移方式取最大值
    f ( i , 1 ) = m a x { f ( i − 1 , 1 ) + n u m s ( i − 1 ) , f ( i − 1 , 0 ) + n u m s ( i − 1 ) ∗ n u m s ( i − 1 ) } f(i,1) = max \{f(i-1, 1) + nums(i-1), f(i-1,0)+nums(i-1)*nums(i-1) \} f(i,1)=max{f(i1,1)+nums(i1),f(i1,0)+nums(i1)nums(i1)}

小贪心,使用了操作肯定比没使用操作的状态大,所以最后汇总只需要在使用了的状态里取最大值

复杂度

时间复杂度: O ( N ) O(N) O(N)

空间复杂度: O ( N ) O(N) O(N)

代码

class Solution {
    public int maxSumAfterOperation(int[] nums) {
        int n = nums.length;
        int res = Integer.MIN_VALUE;
        int[][] f = new int[n + 1][2];
        for (int i = 1; i <= n; i++) {            
            f[i][0] = Math.max(f[i - 1][0] + nums[i - 1], 0);
            f[i][1] = Math.max(f[i - 1][1] + nums[i - 1], f[i - 1][0] + nums[i - 1] * nums[i - 1]);
            res = Math.max(res, f[i][1]);
        }
        return res;
    }
}

解法二:滚动变量优化

思想

由解法一可得,各个状态转移的递推公式

f[i][0] = max(f[i - 1][0] + nums[i - 1], 0);
f[i][1] = max(f[i - 1][1] + nums[i - 1], f[i - 1][0] + nums[i - 1] * nums[i - 1]);

不难发现,第 i i i 层循环的状态只依赖于第 i − 1 i-1 i1 层循环的状态,所以可由两组变量滚动交替更新。

复杂度

时间复杂度: O ( N ) O(N) O(N)

空间复杂度: O ( 1 ) O(1) O(1)

代码

class Solution {
    public int maxSumAfterOperation(int[] nums) {
        int n = nums.length;
        int res = Integer.MIN_VALUE;
        int a = 0, b = 0;
        for (int i = 1; i <= n; i++) {            
            int x = a, y = b;
            a = Math.max(x + nums[i - 1], 0);
            b = Math.max(y + nums[i - 1], x + nums[i - 1] * nums[i - 1]);
            res = Math.max(res, b);
        }
        return res;
    }
}   
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值