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

题目链接

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

题目描述

给你一个下标从 0 0 0 开始的整数数组 n u m s nums nums 和一个正整数 x x x 。

一开始 在数组的位置 0 0 0 处,你可以按照下述规则访问数组中的其他位置:

  • 如果你当前在位置 i i i ,那么你可以移动到满足 i < j i < j i<j 的 任意 位置 j j j 。
  • 对于你访问的位置 i i i ,你可以获得分数 n u m s i numsi numsi
  • 如果你从位置 i i i 移动到位置 j j j 且 n u m s i numsi numsi 和 n u m s j numsj numsj奇偶性 不同,那么你将失去分数 x x x 。

请你返回你能得到的 最大 得分之和。

注意 ,你一开始的分数为 n u m s 0 nums0 nums0

示例 1:
复制代码
输入:nums = [2,3,6,1,9,2], x = 5
输出:13
解释:我们可以按顺序访问数组中的位置:0 -> 2 -> 3 -> 4 。
对应位置的值为 2 ,6 ,1 和 9 。因为 6 和 1 的奇偶性不同,所以下标从 2 -> 3 让你失去 x = 5 分。
总得分为:2 + 6 + 1 + 9 - 5 = 13 。
示例 2:
复制代码
输入:nums = [2,4,6,8], x = 3
输出:20
解释:数组中的所有元素奇偶性都一样,所以我们可以将每个元素都访问一次,而且不会失去任何分数。
总得分为:2 + 4 + 6 + 8 = 20 。
提示:
  • 2 ≤ n u m s . l e n g t h ≤ 1 0 5 2 \leq nums.length \leq 10^5 2≤nums.length≤105
  • 1 ≤ n u m s i , x ≤ 1 0 6 1 \leq numsi, x \leq 10^6 1≤numsi,x≤106

解法一:动态规划

定义 f i j fij fij 为前 n u m s nums nums 前 i i i 个元素,最后一个元素是奇数或者偶数 ( j = 0 , 是偶数 ; j = 1 , 是奇数 ) (j = 0,是偶数;j = 1,是奇数) (j=0,是偶数;j=1,是奇数) 的最大分数和。注意:最后一个元素不一定是第 i i i 个元素。

对于第 i i i 个元素 n u m s i numsi numsi,用 k k k 表示它的奇偶性质:

  • f i k = m a x ( f i − 1 k , f i − 1 k x o r 1 − x ) + n u m s i fik = max(fi -1k, fi-1k\\ xor\\ 1 - x) + numsi fik=max(fi−1k,fi−1k xor 1−x)+numsi
  • f i k x o r 1 = f i − 1 k x o r 1 fik\\ xor\\ 1 = fi-1k\\ xor\\ 1 fik xor 1=fi−1k xor 1

由于 f f f 默认下标是从 1 1 1 开始的,而 n u m s nums nums 是从 0 0 0 开始的,所以需要做下转换:

  • f i k = m a x ( f i − 1 k , f i − 1 k x o r 1 − x ) + n u m s i − 1 fik = max(fi -1k, fi-1k\\ xor\\ 1 - x) + numsi - 1 fik=max(fi−1k,fi−1k xor 1−x)+numsi−1
  • f i k x o r 1 = f i − 1 k x o r 1 fik\\ xor\\ 1 = fi-1k\\ xor\\ 1 fik xor 1=fi−1k xor 1

注意: f f f 需要初始化为一个相对较小的数字,因为 f i − 1 k x o r 1 − x fi-1k\\ xor\\ 1 - x fi−1k xor 1−x 是有可能小于 0 0 0 的,如果 f f f 全部初始化为 0 0 0,并且此时恰好 f i − 1 k = 0 fi -1k = 0 fi−1k=0,最终就会得到一个错误的结果 。本来这里的答案应该是 f i k = f i − 1 k x o r 1 − x + n u m s i − 1 fik = fi-1k\\ xor\\ 1 - x + numsi - 1 fik=fi−1k xor 1−x+numsi−1,最终却变成了 f i k = 0 + n u m s i − 1 fik = 0 + numsi - 1 fik=0+numsi−1。最终结果就会比标准答案偏大。

比如这个用例:

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

C++代码:

cpp 复制代码
using LL = long long;

class Solution {
public:
    long long maxScore(vector<int>& nums, int x) {
        int n = nums.size();
        vector<vector<LL>> f(n + 1, vector<LL>(2, -1e18));

        f[1][nums[0] & 1] = nums[0];
        for(int i = 2;i <= n;i++)
        {
            int k = (nums[i - 1] & 1);
            f[i][k] = max(f[i - 1][k], f[i - 1][k ^ 1] - x) + nums[i - 1];
            f[i][k ^ 1] = f[i - 1][k ^ 1];
        }

        return max(f[n][0], f[n][1]);
    }
};

解法二:动态规划 + 一维空间

我们注意到 f i k fik fik 实际只会依赖于 f i − 1 k fi-1k fi−1k 和 f i − 1 k x o r 1 fi - 1k\\ xor\\ 1 fi−1k xor 1,所以我们可以直接降维,使用两个变量来模拟。

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

C++代码:

cpp 复制代码
using LL = long long;

class Solution {
public:
    long long maxScore(vector<int>& nums, int x) {
        int n = nums.size();
        vector<vector<LL>> f(n + 1, vector<LL>(2, -1e18));

        f[1][nums[0] & 1] = nums[0];
        for(int i = 2;i <= n;i++)
        {
            int k = (nums[i - 1] & 1);
            f[i][k] = max(f[i - 1][k], f[i - 1][k ^ 1] - x) + nums[i - 1];
            f[i][k ^ 1] = f[i - 1][k ^ 1];
        }

        return max(f[n][0], f[n][1]);
    }
};

Python3代码:

python3 复制代码
class Solution:
    def maxScore(self, nums: List[int], x: int) -> int:
        n = len(nums)
        f = [-inf] * 2
        f[nums[0] & 1] = nums[0]

        for i in range(1, n):
            k = (nums[i] & 1)
            f[k] = max(f[k], f[k ^ 1] - x) + nums[i]
        
        return max(f[0], f[1])
相关推荐
随意起个昵称1 小时前
线性dp-LIS题目2(导弹拦截III)
算法·动态规划·图论
stolentime4 小时前
CF2066D1 Club of Young Aircraft Builders (easy version)题解
c++·算法·动态规划·组合数学
迈巴赫车主5 小时前
蓝桥杯21241灯塔java
java·开发语言·数据结构·算法·职场和发展·蓝桥杯·动态规划
8Qi88 小时前
LeetCode 518:零钱兑换 II(Coin Change II)—— 题解 ✅
java·算法·leetcode·动态规划·完全背包
8Qi810 小时前
LeetCode 474:一和零(Ones and Zeroes)—— 题解 ✅
算法·leetcode·职场和发展·动态规划·01背包
stolentime10 小时前
CF2066D2 Club of Young Aircraft Builders (hard version)题解
c++·算法·动态规划·组合数学
8Qi810 小时前
LeetCode 377:组合总和 Ⅳ(Combination Sum IV)—— 题解 ✅
算法·leetcode·动态规划·完全背包
8Qi81 天前
LeetCode 416:分割等和子集 —— (0-1背包)
java·算法·leetcode·动态规划·背包问题·01背包
8Qi81 天前
LeetCode 62 & 63:不同路径 I & II(含障碍物)
java·算法·leetcode·职场和发展·动态规划
8Qi81 天前
LeetCode 96:不同的二叉搜索树(Unique Binary Search Trees)—— 题解 ✅
算法·leetcode·职场和发展·动态规划