第十周:[Leetcode]486. Predict the Winner

Given an array of scores that are non-negative integers. Player 1 picks one of the numbers from either end of the array followed by the player 2 and then player 1 and so on. Each time a player picks a number, that number will not be available for the next player. This continues until all the scores have been chosen. The player with the maximum score wins.
Given an array of scores, predict whether player 1 is the winner. You can assume each player plays to maximize his score.
Example 1:
Input: [1, 5, 2]
Output: False
Explanation: Initially, player 1 can choose between 1 and 2.
If he chooses 2 (or 1), then player 2 can choose from 1 (or 2) and 5. If player 2 chooses 5, then player 1 will be left with 1 (or 2).
So, final score of player 1 is 1 + 2 = 3, and player 2 is 5.
Hence, player 1 will never be the winner and you need to return False.
Example 2:
Input: [1, 5, 233, 7]
Output: True
Explanation: Player 1 first chooses 1. Then player 2 have to choose between 5 and 7. No matter which number player 2 choose, player 1 can choose 233.
Finally, player 1 has more score (234) than player 2 (12), so you need to return True representing player1 can win.

解法一:直接模拟。每次两个选手都从可以选的数组两端挑选一个数字(不是最先的就是最后的一个),直接模拟这样一个过程,选手一挑完,选手二挑,直到最后看哪名选手的总和高,使用递归来实现整个模拟过程。

class Solution {
public:
    bool PredictTheWinner(vector<int>& nums) {
    return player1_win(nums, 0, nums.size() - 1, 0, 0);
}

bool player1_win(vector<int>& nums,int start,int end,int sum1,int sum2){
    if(start > end)
        return sum1 >= sum2;
    bool pick_start_player2_win = player2_win(nums,start + 1,end,sum1 + nums[start],sum2);
    bool pick_end_player2_win = player2_win(nums,start,end - 1,sum1 + nums[end],sum2);
    return (!pick_start_player2_win || !pick_end_player2_win);
}

bool player2_win(vector<int>& nums,int start,int end,int sum1, int sum2){
    if(start > end)
        return sum2 > sum1;
    bool pick_start_player1_win = player1_win(nums,start + 1,end,sum1,sum2 + nums[start]);
    bool pick_end_player1_win = player1_win(nums,start,end - 1,sum1,sum2 + nums[end]);
    return (!pick_start_player1_win || !pick_end_player1_win);
}
};

解法二:动态规划。比较最后选手一的数字总和是否大于选手二的,这一过程可以类比成,维护一个特殊变量,选手一选一个数字,在这个变量基础上加该值,选手二选一个数字,在这个变量基础上减该值,最后该变量若不为负,则选手一获胜。dp[i][j]数组中的值代表从位置i到j这段数组中,这个特殊变量的最大值。由于选手一选之前肯定是选手二选,所以dp[i][j] = 该次选的值+(-上一步选手二选完后的dp值),每次选值有两种可能,选择下标为i的第一个元素或者下标为j的最后一个元素,可得动态转移方程为:
dp[i][j] = max(nums[i]-dp[i+1][j],nums[j]-dp[i][j-1])
当i==j时,dp[i][j] = nums[i],这一步应在初始化dp数组时做。

class Solution {
public:
    bool PredictTheWinner(vector<int>& nums) {
    int dp[nums.size()][nums.size()] = {0};
    for(int i = 0;i < nums.size();i++)
        dp[i][i] = nums[i];
    for(int i = nums.size() - 2;i >= 0;i--)
        for(int j = i + 1; j < nums.size();j++)
            dp[i][j] = max(nums[i] - dp[i+1][j],nums[j] - dp[i][j-1]);
    return dp[0][nums.size() - 1] >= 0;
}
};
点赞