算法概论week10 | leetcode 877. Stone Game

题目描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


分析

这道题是比较有技巧性的。由于题目规定石子堆数为偶数,那么可以把石子堆分成两种堆——奇数堆和偶数堆,先开始的人可以分别计算这两种堆的总和,如果奇数堆的和大,那么就可以一直选择奇数堆的石子堆(为什么可以一直选择奇数堆的石子呢?因为堆数为偶数,两端的堆就分别属于奇数堆和偶数堆,先开始的人拿走一堆后,两端的堆就只属于奇数堆或只属于偶数堆了,后开始的人拿走一堆后,先开始的人又可以选择拿奇数的堆或偶数的堆了),反之亦然,所以谁先开始,谁就能胜。这题Alex先开始,所以可以直接返回true。

用动态规划可以解决更一般化的问题,如石子堆数不一定是偶数,不仅要判断胜负,还要计算得分等等。那么子问题是什么呢?我们可以先计算出连续石子堆总数为1的胜负情况(Alex一定胜对吧!此时Alex最终比Lee多得到的石子数就等于这个石子堆的石子数,我们把它称为分数),然后计算连续石子堆总数为2的情况(Alex同样可以很轻松地选择总数大的那一堆,Alex的分数也很容易计算),接着计算连续堆总数为3的情况(得思考一下了,Alex可以选择第一堆或者第三堆,选完之后,就还剩下两堆了,这时Lee同样也会做出最佳选择,也就是说,Lee的暂时得分可以通过前面计算出的,连续石子堆总数为2的情况得出!那么Alex的得分,就等于Alex选出的那一堆的石子数,减去Lee的暂时得分),以此类推,可以算出连续堆总数为4、5、6……n-1的情况,最后就能算出连续堆总数为n的情况啦。

我们用dp[ i ][ j ]表示连续石子堆为原石子堆中第i堆到第j堆(包含i,j)时,先开始的人的得分。当只有一堆时,也就是i = j时,dp[ i ][ j ] 就等于piles[ i ],当有n堆时,dp[ i ][ j ]可以由n-1堆时的先手得分算出,选最左边的堆时,得分为piles[ i ] - dp[ i + 1 ][ j ],选最右边的堆时,得分为piles[ j ] - dp[ i ][ j - 1 ], dp[ i ][ j ] 取两者中分数大者。


C++代码

class Solution {
public:
    bool stoneGame(vector<int>& piles) {
        int l = piles.size();
        int dp[l][l] = {};
        for(int i = 0; i < l; i++) dp[i][i] = piles[i];
        for(int n = 1; n < l; n++) 
            for(int i = 0; i < l - n; i++) 
                dp[i][i + n] = max(piles[i] - dp[i + 1][i + n], piles[i + n] - dp[i][i + n - 1]);
        return dp[0][l - 1] > 0;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值