区间动态规划例题:预测赢家问题
字数 1307 2025-10-26 09:00:43

区间动态规划例题:预测赢家问题

题目描述
给定一个非负整数数组nums,两个玩家轮流从数组的两端取数(每次只能取最左或最右端的数字),取到的数字就是该玩家的得分。双方都采取最优策略,如果先手玩家能获胜(即总得分大于或等于后手玩家),则返回true,否则返回false。假设数组长度不超过20。

解题思路
这个问题可以用区间动态规划解决。核心思想是定义dp[i][j]表示在子数组nums[i..j]上,当前行动的玩家(不一定是先手)能比对手多得的分数。通过比较最终差值是否>=0来判断先手是否获胜。

详细解题步骤

  1. 定义状态
    定义dp[i][j]为当数组剩下部分为nums[i]到nums[j]时,当前行动的玩家可以比对手多得的最高分数。

  2. 状态转移方程
    当轮到当前玩家行动时,他有两种选择:

  • 取左端的nums[i]:那么对手会在剩下的nums[i+1..j]上采取最优策略,当前玩家比对手多的分数为 nums[i] - dp[i+1][j]
  • 取右端的nums[j]:那么对手会在剩下的nums[i..j-1]上采取最优策略,当前玩家比对手多的分数为 nums[j] - dp[i][j-1]

因此状态转移方程为:
dp[i][j] = max(nums[i] - dp[i+1][j], nums[j] - dp[i][j-1])

  1. 边界条件
    当区间长度为1时(i = j),当前玩家只能取这个数,比对手多的分数就是这个数本身:
    dp[i][i] = nums[i]

  2. 计算顺序
    由于dp[i][j]依赖于dp[i+1][j]和dp[i][j-1],我们需要从小区间向大区间计算:

  • 按区间长度len从1到n遍历
  • 对于每个长度,遍历所有起始位置i
  1. 最终结果
    dp[0][n-1]表示在整个数组上,先手玩家比后手玩家多的分数。如果dp[0][n-1] >= 0,则先手可以获胜。

示例分析
以nums = [1, 5, 2]为例:

  1. 初始化单个元素的区间:
    dp[0][0] = 1, dp[1][1] = 5, dp[2][2] = 2

  2. 计算长度为2的区间:

    • [0,1]:max(1-dp[1][1], 5-dp[0][0]) = max(1-5, 5-1) = max(-4, 4) = 4
    • [1,2]:max(5-dp[2][2], 2-dp[1][1]) = max(5-2, 2-5) = max(3, -3) = 3
  3. 计算长度为3的区间[0,2]:
    max(1-dp[1][2], 2-dp[0][1]) = max(1-3, 2-4) = max(-2, -2) = -2

最终dp[0][2] = -2 < 0,说明先手玩家无法获胜。

算法实现要点

  • 使用二维dp数组,大小为n×n
  • 按区间长度从小到大填充dp表
  • 最终判断dp[0][n-1] >= 0

这种方法的时间复杂度是O(n²),空间复杂度是O(n²),能够高效解决这个问题。

区间动态规划例题:预测赢家问题 题目描述 给定一个非负整数数组nums,两个玩家轮流从数组的两端取数(每次只能取最左或最右端的数字),取到的数字就是该玩家的得分。双方都采取最优策略,如果先手玩家能获胜(即总得分大于或等于后手玩家),则返回true,否则返回false。假设数组长度不超过20。 解题思路 这个问题可以用区间动态规划解决。核心思想是定义dp[ i][ j]表示在子数组nums[ i..j ]上,当前行动的玩家(不一定是先手)能比对手多得的分数。通过比较最终差值是否>=0来判断先手是否获胜。 详细解题步骤 定义状态 定义dp[ i][ j]为当数组剩下部分为nums[ i]到nums[ j ]时,当前行动的玩家可以比对手多得的最高分数。 状态转移方程 当轮到当前玩家行动时,他有两种选择: 取左端的nums[ i]:那么对手会在剩下的nums[ i+1..j]上采取最优策略,当前玩家比对手多的分数为 nums[ i] - dp[ i+1][ j ] 取右端的nums[ j]:那么对手会在剩下的nums[ i..j-1]上采取最优策略,当前玩家比对手多的分数为 nums[ j] - dp[ i][ j-1 ] 因此状态转移方程为: dp[ i][ j] = max(nums[ i] - dp[ i+1][ j], nums[ j] - dp[ i][ j-1 ]) 边界条件 当区间长度为1时(i = j),当前玩家只能取这个数,比对手多的分数就是这个数本身: dp[ i][ i] = nums[ i ] 计算顺序 由于dp[ i][ j]依赖于dp[ i+1][ j]和dp[ i][ j-1 ],我们需要从小区间向大区间计算: 按区间长度len从1到n遍历 对于每个长度,遍历所有起始位置i 最终结果 dp[ 0][ n-1]表示在整个数组上,先手玩家比后手玩家多的分数。如果dp[ 0][ n-1 ] >= 0,则先手可以获胜。 示例分析 以nums = [ 1, 5, 2 ]为例: 初始化单个元素的区间: dp[ 0][ 0] = 1, dp[ 1][ 1] = 5, dp[ 2][ 2 ] = 2 计算长度为2的区间: [ 0,1]:max(1-dp[ 1][ 1], 5-dp[ 0][ 0 ]) = max(1-5, 5-1) = max(-4, 4) = 4 [ 1,2]:max(5-dp[ 2][ 2], 2-dp[ 1][ 1 ]) = max(5-2, 2-5) = max(3, -3) = 3 计算长度为3的区间[ 0,2 ]: max(1-dp[ 1][ 2], 2-dp[ 0][ 1 ]) = max(1-3, 2-4) = max(-2, -2) = -2 最终dp[ 0][ 2] = -2 < 0,说明先手玩家无法获胜。 算法实现要点 使用二维dp数组,大小为n×n 按区间长度从小到大填充dp表 最终判断dp[ 0][ n-1 ] >= 0 这种方法的时间复杂度是O(n²),空间复杂度是O(n²),能够高效解决这个问题。