Leetcode 2786. 访问数组中的位置使分数最大(DP 优化)

Leetcode 2786. 访问数组中的位置使分数最大

DP
以每个位置为结尾的序列的分数取决于前方的分数,根据奇偶性计算,取最大值
超时

class Solution {
    public long maxScore(int[] nums, int x) {
        int n = nums.length;
        long dp[] = new long[n];
        Arrays.fill(dp, Integer.MIN_VALUE);
        dp[0] = nums[0];
        long res = nums[0];
        for(int i = 1; i < n; i ++){
            for(int j = 0; j < i; j ++){
                if(nums[j] % 2 == nums[i] % 2){
                    dp[i] = Math.max(dp[i], dp[j] + nums[i]);
                }
                else{
                    dp[i] = Math.max(dp[i], dp[j] + nums[i] - (long)x);
                }
            }
            res = Math.max(res, dp[i]);
        }
        return res;
    }
}

优化

对于 nums[ i ] 来说,该位置的分数取决于前方的序列分数,分为上一个选择是奇数和偶数两种情况,只需max0、max1来分别记录前方的奇偶两种情况最值即可计算出当前位置的分数最值

避免思维误区,计算cur时考虑的不是选或不选的两种情况,而是必定选择 nums[ i ] 作为序列最后一个元素时,取前方奇偶两种可能所获得的分数哪一种更大

由于存在x值较大的情况,计算中可能出现负数,将max0、max1初始化为INT_MIN

获取最值后根据 nums[ i ] 的奇偶性选择更新max0或max1
计算max0/1的两种可能时,即使有可能异性-x后的分数更大,但由于存在同性计算 — 两个正数相加,因此max0/1的值必定会增大,直接将cur赋值给max0/1

class Solution {
    public long maxScore(int[] nums, int x) {
        int n = nums.length;
        long max0 = Integer.MIN_VALUE; // 前方偶数结尾的最大分数
        long max1 = Integer.MIN_VALUE; // 前方奇数结尾的最大分数
        if(nums[0] % 2 == 0)
            max0 = nums[0];
        else
            max1 = nums[0];
        long res = nums[0];
        for(int i = 1; i < n; i ++){
            long cur;
            if(nums[i] % 2 == 0){
                cur = Math.max(max0 + nums[i], max1 + nums[i] - x);
                max0 = cur;
                // max0 = Math.max(max0, cur);
                // 同性情况max0+nums[i],正数求和计算导致cur必然大于max0,省去Max计算
            }
            else{
                cur = Math.max(max0 + nums[i] - x, max1 + nums[i]);
                max1 = cur;
            }
            res = Math.max(res, cur);
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值