leetcode.877 石子游戏

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

示例:

输入:[5,3,4,5]

输出:true

解释: 亚历克斯先开始,只能拿前 5 颗或后 5 颗石子 。 假设他取了前 5 颗,这一行就变成了 [3,4,5] 。 如果李拿走前 3 颗,那么剩下的是 [4,5],亚历克斯拿走后 5 颗赢得 10 分。 如果李拿走后 5 颗,那么剩下的是 [3,4],亚历克斯拿走后 4 颗赢得 9 分。 这表明,取前 5 颗石子对亚历克斯来说是一个胜利的举动,所以我们返回 true 。

链接:https://leetcode-cn.com/problems/stone-game

【思路】

1.dp问题。首先,每次有两种取法,要么选最前一堆石子,要么取最后一堆石子。由于这里涉及到两个先后对象,因此需要三维数组来表示每次的状态,从编号为i堆石子到编号为j堆石子,dp[i][j][0]表示先拿者,dp[i][j][1]表示后拿者。

2.在每次取过之后需要保证最优情况,用left表示取最前一堆石子,right表示取最后一堆石子。两种情况选值大的一种。这里有状态方程:dp[i][j][0] = max(piles[i] + dp[i+1][j][1], piles[j] + dp[i][j-1][1]);其中,left=piles[i] + dp[i+1][j][1],right=piles[j] + dp[i][j-1][1]。

上述状态方程中,我们考虑从编号i堆石子到j堆石子中,先拿者要选取最优值的情况下,后拿者在此基础上选最优值。因此,

  1. 如果先拿者拿了最前一堆石子,那么后拿者dp[i][j][1]为[i+1,j]中选取最优值,并且此时后拿者具有优先权,即dp[i+1][j][0]。
  2. 如果先拿者拿了最后一堆石子,那么后拿者dp[i][j][1]为[i,j+1]中选取最优值,并且此时后拿者具有优先权,即dp[i][j-1][0]。

最终判断dp[0][pilesSize-1][0]和dp[0][pilesSize-1][1]中那个值大就知道谁拿的石子多,谁获胜。

这里需要注意到一点是这个数组在dp的时候并不是逐行赋值的,由于dp[i][j][0] = max(piles[i] + dp[i+1][j][1], piles[j] + dp[i][j-1][1]);那么在赋值i,j时需要知道i+1,j和i,j-1的值了。简单画图可以知道是按照对角线赋值的。那么整个递归方式如下代码所示。

bool stoneGame(int* piles, int pilesSize){
    int i,j,l;
    int dp[pilesSize][pilesSize][2];
    int left,right;
    for(i=0;i<pilesSize;i++){
        dp[i][i][0]=piles[i];
        dp[i][i][1]=0;
    }
    for(l=1;l<pilesSize;l++){
        for(i=0;i<pilesSize-l;i++){
            j=i+l;
            left=piles[i]+dp[i+1][j][1];
            right=piles[j]+dp[i][j-1][1];
            if(left>right){//选择值大的一种情况,对于特定的i,j需要更新以下两个变量
                dp[i][j][0]=left;
                dp[i][j][1]=dp[i+1][j][0];
            }
            else{
                dp[i][j][0]=right;
                dp[i][j][1]=dp[i][j-1][0];
            }
        }
    }
    if(dp[0][pilesSize-1][0]>dp[0][pilesSize-1][1])//如果先选的人最终值大于后选者,返回true
        return true;
    else 
        return false;
}
发布了129 篇原创文章 · 获赞 105 · 访问量 23万+

猜你喜欢

转载自blog.csdn.net/sunshine_lyn/article/details/104185519