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

Solutions

🧠 Cpp

class Solution
{

    std::map<int, bool> cache; 
public:
    //DP solution
    //very simullar to "Climbing Stairs"
    bool winnerSquareGame(int n)
    {
        //DP cache check
        auto found = cache.find(n);
        if(found != end(cache))
            return found->second;

        //if square
        double n_sqrt = sqrt(double(n));
        if( n_sqrt - int(n_sqrt) == 0 )
            cache[n] = true;
        //iterate over all squares that we can take (all variants)
        //if there at leaest one variant where we win, we win
        else
        {
            bool i_won = false;
            vector<int> stones_to_take;
            for(int i = 1; i*i < n; ++i)
                stones_to_take.push_back(i*i);

            //start with the bigest number of stones we can take
            //and iterate down
            for(auto stone_num = rbegin(stones_to_take);
                stone_num < rend(stones_to_take);
                ++stone_num)
            {
                //check if next player lose if we take i*i stones
                if(!winnerSquareGame(n - *stone_num))
                {
                    i_won = true;
                    break;
                }
            }
            cache[n] = i_won;
        }

        return cache[n];

    }
};

Last updated