leetcode
leetcode 2401 ~ 2450
访问数组中的位置使分数最大

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

难度:

标签:

题目描述

You are given a 0-indexed integer array nums and a positive integer x.

You are initially at position 0 in the array and you can visit other positions according to the following rules:

  • If you are currently in position i, then you can move to any position j such that i < j.
  • For each position i that you visit, you get a score of nums[i].
  • If you move from a position i to a position j and the parities of nums[i] and nums[j] differ, then you lose a score of x.

Return the maximum total score you can get.

Note that initially you have nums[0] points.

 

Example 1:

Input: nums = [2,3,6,1,9,2], x = 5
Output: 13
Explanation: We can visit the following positions in the array: 0 -> 2 -> 3 -> 4.
The corresponding values are 2, 6, 1 and 9. Since the integers 6 and 1 have different parities, the move 2 -> 3 will make you lose a score of x = 5.
The total score will be: 2 + 6 + 1 + 9 - 5 = 13.

Example 2:

Input: nums = [2,4,6,8], x = 3
Output: 20
Explanation: All the integers in the array have the same parities, so we can visit all of them without losing any score.
The total score is: 2 + 4 + 6 + 8 = 20.

 

Constraints:

  • 2 <= nums.length <= 105
  • 1 <= nums[i], x <= 106

代码结果

运行时间: 166 ms, 内存: 30.7 MB


/*
 * 思路:
 * 使用Java Stream API来实现同样的逻辑。
 * 我们将创建一个动态规划数组dp来存储每个位置的最大得分。
 * 使用stream的方式来遍历和计算每个位置的最大得分。
 */

import java.util.stream.IntStream;

public class MaxScoreStream {
    public int maxScore(int[] nums, int x) {
        int n = nums.length;
        int[] dp = new int[n];
        dp[0] = nums[0];

        IntStream.range(1, n).forEach(j -> {
            dp[j] = nums[j];
            dp[j] = IntStream.range(0, j)
                    .map(i -> (nums[i] % 2) != (nums[j] % 2) ? dp[i] + nums[j] - x : dp[i] + nums[j])
                    .max()
                    .orElse(dp[j]);
        });

        return IntStream.of(dp).max().orElse(0);
    }
}

解释

方法:

本题解采用动态规划的思路来计算最大得分。定义两个变量 oddmax 和 evenmax,分别存储到达当前位置时,如果当前位置是奇数或偶数时能得到的最大分数。初始化时,根据 nums[0] 的奇偶性来设定 oddmax 和 evenmax 的初始值。遍历数组的每一个元素,根据当前元素的奇偶性更新 oddmax 和 evenmax。如果当前元素是奇数,则 oddmax 可以由前一个奇数直接加上当前值或由前一个偶数转换而来(减去x分)。同理,如果当前元素是偶数,则 evenmax 可以由前一个偶数直接加或由前一个奇数转换而来。最后,返回 oddmax 和 evenmax 中的较大值作为最终答案。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
为什么选择动态规划作为解决这个问题的方法?
动态规划是解决这种类型问题的一个有效方法,因为它能够处理决策过程中的状态转移。具体来说,每次访问数组中的一个元素时,你都面临一个选择:根据当前元素的奇偶性来更新你的得分。动态规划允许我们通过将大问题分解成相似的子问题,并保存这些子问题的解(这里是奇数和偶数的最大分数),从而有效地解决问题。这种方法特别适合于这个问题,因为每一步的最优决策依赖于前一步的状态,而不是从头到当前位置的完整历史。
🦆
在动态规划的过程中,如何保证 oddmax 和 evenmax 只通过前一个状态更新,而不会被其他早期状态影响?
在动态规划的实现中,oddmax 和 evenmax 每次只根据前一个状态(即上一步的 oddmax 和 evenmax)来更新。这是通过在每一步中重新计算 these 两个变量并基于当前元素的奇偶性来决定如何更新来实现的。这种方法确保了每个状态的更新仅依赖于直接前驱的状态,避免了早期状态的直接影响,从而保持了状态转移的正确性和效率。
🦆
为什么在初始化时,未选择的奇数或偶数的起始最大分数是 -x 而不是 0 或其他值?
在这个问题中,-x 代表了一种惩罚或成本,当你从一个奇数状态转移到一个偶数状态或反之时会扣除这个值。在初始化时,如果第一个元素是奇数,我们将 oddmax 初始化为该元素的值,因为这是一个有效的起点,而将 evenmax 设置为 -x,表示如果我们非要从一个奇数状态转为偶数状态,我们需要付出的代价。反之亦然。这种初始化方法反映了从一个不存在的相反状态转换到当前状态的代价,是问题逻辑的一部分,确保了动态规划在开始阶段就能正确地评估各种转换的成本。
🦆
动态规划中,更新 oddmax 和 evenmax 的表达式是否考虑了所有可能的状态转移?
是的,更新表达式考虑了所有必要的状态转移。对于每个新的元素,根据其奇偶性,我们考虑了保持当前状态(即奇数加奇数或偶数加偶数)或改变当前状态(即奇数加偶数或偶数加奇数,并扣除相应的成本 x)。这两种情况都被涵盖在更新 oddmax 和 evenmax 的逻辑中,确保了无论当前元素是奇数还是偶数,都能得到正确的最大分数计算。

相关问题