算法初探LeetCode-预测赢家

93 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第10天,点击查看活动详情

LeetCode486:预测赢家

给你一个整数数组 nums 。玩家 1 和玩家 2 基于这个数组设计了一个游戏。

玩家 1 和玩家 2 轮流进行自己的回合,玩家 1 先手。开始时,两个玩家的初始分值都是 0 。每一回合,玩家从数组的任意一端取一个数字(即,nums[0] 或 nums[nums.length - 1]),取到的数字将会从数组中移除(数组长度减 1 )。玩家选中的数字将会加到他的得分上。当数组中没有剩余数字可取时,游戏结束。

如果玩家 1 能成为赢家,返回 true 。如果两个玩家得分相等,同样认为玩家 1 是游戏的赢家,也返回 true 。你可以假设每个玩家的玩法都会使他的分数最大化。

示例 1:

输入:nums = [1,5,2]
输出:false
解释:一开始,玩家 1 可以从 1 和 2 中进行选择。
如果他选择 2(或者 1 ),那么玩家 2 可以从 1(或者 2 )和 5 中进行选择。如果玩家 2 选择了 5 ,那么玩家 1 则只剩下 1(或者 2 )可选。 
所以,玩家 1 的最终分数为 1 + 2 = 3,而玩家 25 。
因此,玩家 1 永远不会成为赢家,返回 false 。

示例 2:

输入:nums = [1,5,233,7]
输出:true
解释:玩家 1 一开始选择 1 。然后玩家 2 必须从 57 中进行选择。无论玩家 2 选择了哪个,玩家 1 都可以选择 233 。
最终,玩家 1234 分)比玩家 212 分)获得更多的分数,所以返回 true,表示玩家 1 可以成为赢家。

提示:

  • 1<=nums.length<=20 1 <= nums.length <= 20
  • 0<=nums[i]<=107 0 <= nums[i] <= 10^7

思路分析

分析题意使用动态规划方式为最优

定义二维数组dp,其行数和列数都等于数组的长度,dp[i][j] 表示当数组剩下的部分为下标 i 到下标 j 时,当前玩家与另一个玩家的分数之差的最大值 dp的转移就是取左边和取右边的最大者
可以说递归是自上而下,这道题就是从整个数组到单个数,动态规划是自底而上,那么就是从单个数到整个数组规划 初始化,当i和j相等的时候,只能取这个值,那么就是nums[i] 对比元素时从下到上,从左到右转移。

算法代码

public boolean PredictTheWinner(int[] nums) {
    int length = nums.length;
    int[] dp = new int[length];
    for (int i = 0; i < length; i++) {
        dp[i] = nums[i];
    }
    for (int i = length - 2; i >= 0; i--) {
        for (int j = i + 1; j < length; j++) {
            dp[j] = Math.max(nums[i] - dp[j], nums[j] - dp[j - 1]);
        }
    }
    return dp[length - 1] >= 0;
}

算法复杂度

  • 时间复杂度:O(N2)O(N^2)
  • 空间复杂度:O(N)O(N)

掘金(JUEJIN)一起进步,一起成长!