leetcode 石子游戏 II

题目链接
思路:动态规划
分析:首先,M的更新公式已经给我们了,M=max(M,X),然后X的范围也给我们了,[1,2*M],那么我们可以枚举X
我们使用三维dp
dp[i][j][0] 表示从第i堆石头开始,当M=j的时候,先手能取到的最大石头数目
dp[i][j][1] 表示从第i堆石头开始,当M=j的时候,后手能取到的最大石头数目

并且要清楚一个问题,就是这一轮的先手在下一轮就是后手,因为这里枚举一个当前的X后,进入下一轮选择,那么也就是这一轮的后手选择,然后得到下一轮先手与后手的最大,然后从 每次下一轮枚举出来的后手(也就是当前先手)最大加上当前 前X堆石头数量,挑选最大的即可。
代码:

class Solution {
    // dp[i][j][0]表示 piles[i~end],m=j先手获得的最大石头数量;
    // dp[i][j][1]表示 piles[i~end],m=j后手获得的最大石头数量;
    int[][][] dp;
    public int stoneGameII(int[] piles) {
        if (piles.length == 1) {
            return piles[0];
        }
        // dp[i][j][0]  先手的在 i~j 闭区间 m=j的时候 能拿到的最大
        // dp[i][j][1]  后手的在 i~j 闭区间 m=j的时候 能拿到的最大
        dp = new int[piles.length][piles.length][2];
        return dfs(piles, 0, 1)[0];
    }

    public int[] dfs(int[] piles, int start, int M) {
        if(start == piles.length){
            return new int[]{0,0};
        }

        if(dp[start][M][0]!=0){
            return dp[start][M];
        }

        int[] max = {0,0};

        int sum = 0;

        for(int x = 1; x <= 2 * M;x++) {
            int index = start + x - 1;

            if(index == piles.length){
                break;
            }

            sum = sum + piles[index];

            //下一轮的结果 tem[0]是下一轮的先手,tem[1]是下一轮的后手    下一轮的后手也就是这一轮的先手
            int[] tem = dfs(piles, start + x, Math.max(M, x));

            //当前累加的加上下一轮自己能选择的最大的
            if(sum + tem[1] > max[0]){
                //当前累加的加上下一轮自己能选择的最大的,那么肯定是选择  加起来最大的  那么max[1]肯定会因此选择下一轮先手最大的
                max[0] = sum + tem[1];
                max[1] = tem[0];
            }
        }

        dp[start][M] = max;
        return dp[start][M];
    }
}

思路二:
思路:动态规划
分析:模拟一下简单的,如果只有1堆石头,那么直接拿走,如果只有2堆石头,也是直接拿走,如果有3堆。。。
此时还和M有关,所以这里可以得出,需要记录此时有几堆石头,还有现在的M是多少。
那么我们定义一个dp, dp[i][j]表示当前在第i堆石头,M=j的时候,能拿到的最大值,动态规划需要从小往大走,所以这里的i从最后一个开始往前移动。
代码:

public int stoneGameII(int[] piles) {

        int len = piles.length;
        if (len == 1) {
            return piles[0];
        }

        int[][] dp = new int[len][len+1];

        int sum = 0;
        for(int start = len -1; start >=0 ;start--){
            sum = sum + piles[start];
            
            for(int M = 1; M <len;M++){
            	//此时说明可以全部拿走,
                if(start + 2*M >len){
                    dp[start][M] = sum;
                }else{
                    for(int X = 1; X < 2*M;X++){
                        // sum - 对方最大,就是自己最大
                        dp[start][M] = Math.max(dp[start][M], sum-dp[start+X][Math.max(X,M)]);
                    }
                }
            }
        }
        return dp[0][1];
    }

好好学习。
不打扰是我的温柔。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值