JAVA程序设计:石子游戏 VIII(LeetCode:5766)

Alice 和 Bob 玩一个游戏,两人轮流操作, Alice 先手 。

总共有 n 个石子排成一行。轮到某个玩家的回合时,如果石子的数目 大于 1 ,他将执行以下操作:

选择一个整数 x > 1 ,并且 移除 最左边的 x 个石子。
将 移除 的石子价值之 和 累加到该玩家的分数中。
将一个 新的石子 放在最左边,且新石子的值为被移除石子值之和。
当只剩下 一个 石子时,游戏结束。

Alice 和 Bob 的 分数之差 为 (Alice 的分数 - Bob 的分数) 。 Alice 的目标是 最大化 分数差,Bob 的目标是 最小化 分数差。

给你一个长度为 n 的整数数组 stones ,其中 stones[i] 是 从左边起 第 i 个石子的价值。请你返回在双方都采用 最优 策略的情况下,Alice 和 Bob 的 分数之差 。

 

示例 1:

输入:stones = [-1,2,-3,4,-5]
输出:5
解释:
- Alice 移除最左边的 4 个石子,得分增加 (-1) + 2 + (-3) + 4 = 2 ,并且将一个价值为 2 的石子放在最左边。stones = [2,-5] 。
- Bob 移除最左边的 2 个石子,得分增加 2 + (-5) = -3 ,并且将一个价值为 -3 的石子放在最左边。stones = [-3] 。
两者分数之差为 2 - (-3) = 5 。
示例 2:

输入:stones = [7,-6,5,10,5,-2,-6]
输出:13
解释:
- Alice 移除所有石子,得分增加 7 + (-6) + 5 + 10 + 5 + (-2) + (-6) = 13 ,并且将一个价值为 13 的石子放在最左边。stones = [13] 。
两者分数之差为 13 - 0 = 13 。
示例 3:

输入:stones = [-10,-12]
输出:-22
解释:
- Alice 只有一种操作,就是移除所有石子。得分增加 (-10) + (-12) = -22 ,并且将一个价值为 -22 的石子放在最左边。stones = [-22] 。
两者分数之差为 (-22) - 0 = -22 。
 

提示:

n == stones.length
2 <= n <= 105
-104 <= stones[i] <= 104

思路:由题目中的规则我们得知,无论alice和bob怎么取,最后的差值一定是最后要取的呢堆石子的价值和(若是bob的话就是价值和的相反数),而两人为了保证分数差能尽可能的达到自己的预期,它们一定会想方设法的使得最后剩下的价值和让对方尽可能小,然而最后一轮的状态一定是和上一轮状态有关的(PS:比赛时把题目想简单了,以为枚举剩下的后缀和就可以了,事实证明我是sb~),因此我们需要考虑每一轮的状态,假设当前轮次为Alice行动,并且已经取到了第i堆,那么他此时就有两种选择:

1.如果Alice没有选择第i堆,那么他需要在[i+1,n)中选择一堆使得他能获得的价值和尽可能大, 此时dp[i]=dp[i+1]

2.假设Alice取了第i堆,那么Bob就可以在[i+1,n)之间取,此时dp[i]=sum[i]-dp[i+1],其中sum[i]为第i堆之前的前缀和

而最后的答案一定是dp[1],这和题目中的规则有关的(第一个人一定要至少取两堆)。

class Solution {
    public int stoneGameVIII(int[] stones) {
        int n = stones.length;
        int[] dp = new int[n];
        int[] sum = new int[n];
        sum[0] = stones[0];
        for (int i = 1; i < n; i++)
            sum[i] = sum[i - 1] + stones[i];
        dp[n - 1] = sum[n - 1];
        for (int i = n - 2; i >= 0; i--)
            dp[i] = Math.max(dp[i + 1], sum[i] - dp[i + 1]);
        return dp[1];
    }
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值