[Leetcode] 877.Stone Game

【第一篇博客纪念】

以此文章的开篇作为纪念,正式开通CSDN。
目前以更新Leetcode上的题目为主,以后还不知道会研究什么。
祝自己九推顺利。
吃饱喝足努力进步。

877. Stone Game

[原题目链接](https://leetcode.com/problems/stone-game/description/)

Alex和Lee用几堆石子在做游戏。偶数堆石子排成一行,每堆都有正整数颗石子piles[i]
游戏以谁手中的石子最多来决出胜负。石子的总数是奇数,所以没有平局。
Alex和Lee轮流进行,Alex先开始。 每回合,玩家从一行的开始或结尾处取走石头。 这种情况一直持续到没有更多的石子堆为止,此时手中石子最多的玩家获胜。
假设Alex和Lee**都发挥出最佳水平**,当Alex赢得比赛时返回 true ,当Lee赢得比赛时返回 false 。

注:

  1. 2 <= piles.length <= 500
  2. piles.length 是偶数。
  3. 1 <= piles[i] <= 500
  4. sum(piles) 是奇数。

解法1: 直接返回true[Accepted]

这个题目有趣的地方在于,通过它给出的限制条件可以直接判断谁能胜利。
Alex是第一个去选择的人,而且piles.length是偶数,这就导致了:Alex可以总是选下标为偶数的piles或者下标为奇数的piles。
举个例子,piles.length=n且为偶数。
如果Alex想去选择下标为偶数的piles,他第一轮可以选择piles[0].之后Lee只能从piles[1]~piles[n-1]中做出选择,而无论哪种选择都可以使得Alex下一轮继续选择下标为偶数的piles。这样循环往复,Alex可以将所有下标为偶数的piles选走,而Lee只能选择下标为奇数的piles。反之亦然。
同时题目还给出了一个条件,就是sum(piles)是奇数。如果sum(piles[even]) > sum(piles[odds])那么Alex选择偶数的piles即可取得胜利,反之选择奇数的piles即可取得胜利。
综上,Alex总是可以赢,直接return true即可AC。

class Solution {
public:
    bool stoneGame(vector<int>& piles) {
        return true;
    }
};

解法2: DP

解法1需要很多的限制条件才可以成立,而且这样解题并不是作者本身的意图,对于一般性情况,本题目可以通过动态规划求解。其中一般情况是指:如果piles.length为奇数该怎么办?或者我们想明确的知道分数的差距又该如何处理?

对于动态规划的题,一般求什么就设什么。在这里我们设dp[i][j]表示从piles[i]到piles[j]你可以比对手多得的最多的分数。这样我们的最终目标是dp[0][n-1]。现在我们需要确定转移方程和初始条件。
piles[i]~piles[j]中,你可以选择piles[i]或者piles[j]
如果你选择了piles[i],那么你的对手就会从piles[i+1]~piles[j]中得到最多的分数,分数差值为piles[i]-dp[i+1][j].(题目要求都发挥最佳水平,所以对于对手而言dp的含义一样。,他会从剩下的piles中选择最多的分数,所以两者做减法。)
如果你选择了piles[j],分数差值为piles[j] - dp[i][j-1].

所以状态转移方程为:

dp[i][j] = max(piles[i] - dp[i + 1][j], piles[j] - dp[i][j - 1])

初始条件为:

当 i == j 时, dp[i][i] = piles[i]
根据上述思路可以很简单的写出代码:

class Solution {
public:
    bool stoneGame(vector<int>& piles) {
        int n = piles.size();
        vector<vector<int>> dp(n, vector<int>(n, 0));
        for (int i = 0; i < n; i++) dp[i][i] = piles[i];
        for (int d = 1; d < n; d++)
            for (int i = 0; i < n - d; i++)
                dp[i][i + d] = max(piles[i] - dp[i + 1][i + d], piles[i + d] - dp[i][i + d - 1]);
        return dp[0][n - 1] > 0;
    }
};

【Attention】

即使最开始知道了状态转移方程,但循环体(特别是循环变量和限制条件仍然存在问题)。最开始时并没有理解为什么要这么写,等到再一次碰到类似题目的时候发现自己仍然写不出来,才知道自己并没有理解真正的题解内涵。我们最开始设置当i==j时,dp[i][i]=piles[i].这是初始条件。然后他的类推方式是通过第一层循环中的d的改变来不断调整i,j之间元素的个数。即d == 1时,我们两个两个一组进行计算,d == 2时,我们三个三个一组进行计算,以此类推。最终得出最后的答案。如图所示:
[Leetcode] 877.Stone Game_第1张图片

你可能感兴趣的:(Leetcode)