LeetCode 486. Predict the Winner

来源:互联网 发布:c语言模块化程序设计 编辑:程序博客网 时间:2024/06/05 03:03

题目:给出一个数组,玩家1和玩家2轮流从数组的两端无放回地抽取一个数字(玩家1先抽),当数组被抽完时计算两个玩家的数字总和,总和数值大者为胜者。现在给出一个数组,预测玩家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.

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.

解题思路:用动态规划解决这个问题。而动态规划的要点是定义问题的子问题,那么下面我们来定义这个问题的子问题。

假设给定数组nums,下面介绍一些参数定义:

f(i,j):假设游戏取值范围是从数组索引 i 到索引 j, 则玩家1抽到的数值的最大总和为f(i,j)(i>j,可以将f理解成一个矩阵,但只会用到上半角);

range_sum(i,j):数组索引 i 到索引 j的数值总和(可以将range_sum理解成一个矩阵,但只会用到上半角);

思想:若要求f(i,j),即目前游戏取值范围是nums[i],nums[i+1],....,nums[j],玩家1要么选nums[i],要么选nums[j],当选择nums[i]时,其最大总和:

f(i,j)=nums[i]+range_sum(i+1,j)-f(i+1,j),

这个怎么理解呢?

当玩家1选择nums[i]后到玩家2选择,那么假设玩家2一定会用最优的抽取方法的到最大总和,这个总和相当于玩家1从nums的i+1位置到j位置开始游戏得到的最大总和,即玩家2抽取的数值总和为f(i+1,j),那么玩家1除了nums[i]外只能得到range_sum(i+1,j)-f(i+1,j);同理,当玩家1选择nums[j]时,抽取数值最大总和:

f(i,j)=nums[j]+range_sum(i,j-1)-f(i,j-1),

综上所述,可将子问题按如下方式定义:

f(i,j)=max{ nums[i]+range_sum(i+1,j)-f(i+1,j) , nums[j]+range_sum(i,j-1)-f(i,j-1) };

以上是用矩阵的计算的,空间复杂度为O(nums.size()*num.size()),可以进一步将空间复杂度优化成O(num.size()),实现代码是优化后的方法;

实现代码如下:

class Solution {public:    bool PredictTheWinner(vector<int>& nums) {        int size = nums.size();        vector<int> range_sum(nums),scores(nums);range_sum.push_back(0);scores.push_back(0);        for(int i = size-1; i > 0; --i){            for(int j = 0; j < i; ++j){                int end=size-i+j;                scores[j] = nums[end]+range_sum[j]-scores[j] > \                nums[j] + range_sum[j+1] - scores[j+1]?\                nums[end]+range_sum[j]-scores[j]:\                nums[j] + range_sum[j+1] - scores[j+1];                range_sum[j] = range_sum[j] + nums[end];            }        }        if(scores[0]>=1.0*range_sum[0]/2) return true;        return false;    }};



0 0
原创粉丝点击