Leetcode 1510 Stone Game IV

Leetcode 1510 Stone Game IV

题目

Alice and Bob take turns playing a game, with Alice starting first.

Initially, there are n stones in a pile. On each player’s turn, that player makes a move consisting of removing any non-zero square number of stones in the pile.

Also, if a player cannot make a move, he/she loses the game.

Given a positive integer n. Return True if and only if Alice wins the game otherwise return False, assuming both players play optimally.

Example 1:
Input: n = 1
Output: true
Explanation: Alice can remove 1 stone winning the game because Bob doesn’t have any moves.

Example 2:
Input: n = 2
Output: false
Explanation: Alice can only remove 1 stone, after that Bob removes the last one winning the game (2 -> 1 -> 0).

Example 3:
Input: n = 4
Output: true
Explanation: n is already a perfect square, Alice can win with one move, removing 4 stones (4 -> 0).

Example 4:
Input: n = 7
Output: false
Explanation: Alice can’t win the game if Bob plays optimally.
If Alice starts removing 4 stones, Bob will remove 1 stone then Alice should remove only 1 stone and finally Bob removes the last one (7 -> 3 -> 2 -> 1 -> 0).
If Alice starts removing 1 stone, Bob will remove 4 stones then Alice only can remove 1 stone and finally Bob removes the last one (7 -> 6 -> 2 -> 1 -> 0).

Example 5:
Input: n = 17
Output: false
Explanation: Alice can’t win the game if Bob plays optimally.

Constraints:
1 <= n <= 10^5

思路

从小的数字往大考虑每个数字的输赢情况,开一个states数组,每个数字记录这个开始时为这个数的情况下按照题目里的规则Alice是输还是赢,分别用0和1表示,数组中值初始化为-1说明还为计算到该值。
考虑题目给的几个例子,Alice先走,首先考虑Alice一步就会赢的情况,就是给的数就是一个完全平方,这时我们把states中的1,4,9,…个元素设置成1。在考虑两步的情况,此时数是两个完全平方相加,所以遍历数组,找到值不为-1的数(他们已经是一个完全平方数了),使用setState()函数在往上面加入一个完全平方数,此时Bob也是最优打法,所有Alice的状态是输,把这些数设置成0。
总结来说,states中值为1的数就是可以被分解为奇数个平方数和的数,值为0的数是只能被分解为偶数个平方和的数;下一轮遍历的时候,在states为1的数的基础上加一个平方数将结果状态设置为0,在states为0的数的基础上加一个平方数将结果的状态设置为1。需要注意的是我们想要状态为0的是只能被分解为偶数个的,所以如果这个状态提前被设置成了0,后来发现有一个奇数个的方法可以将它设置成1,我们就用这种方法,反之则不行,因为规则是Alice先行,它可以决定接下来游戏的顺序,这也是代码中加入判断states[base+i*i] != 1的原因。
举例:
8 = 4 + 4 8 = 4 + 4 8=4+4,此种玩法Alice输
8 = 4 + 1 + 1 + 1 + 1 8 = 4 + 1 + 1 + 1 + 1 8=4+1+1+1+1,此时Alice只要先出1就赢

代码

class Solution {
    public boolean winnerSquareGame(int n) {
        int[] states = new int[n+1];
        Arrays.fill(states, -1);
        setState(n, states, 1, 0); // win in 1 attempt
        boolean flag = true;
        while (flag) {
            flag = false;
            for (int i = 1; i <= n; i++) {
                if (states[i] != -1) {
                    setState(n, states, 1 - states[i], i);
                } else {
                    flag = true;
                }
            }
        return states[n] == 1;
    }
    
    public void setState(int n, int[] states, int state, int base) {
        for (int i = (int) Math.sqrt(n); i >= 1; i--) {
            
            if (base + i*i <= n && states[base+i*i] != 1) {
                states[base + i*i] = state;
            }
        }
    }
}

优化

class Solution {
    public boolean winnerSquareGame(int n) {
        boolean[] dp = new boolean[n + 1];
        for (int i = 0; i <= n; i++){
            if (dp[i]){
                continue;
            }
            for (int k = 1; i + k * k <= n; k++){
                dp[i+k*k] = true;
            }
        }
        return dp[n];
    }
}

来自Leetcode Sample Code,可以看到不需要一次性算出所以一个数的完全平方,两个数的完全平方和… 而是可以从左往右依次计算,遇到false的,往上加个平方数设置为true。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值