Stone Game IV
HardUpdated: Aug 2, 2025
Practice on:
Problem
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.
Examples
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).
Constraints
n == stones.length2 <= n <= 10001 <= stones[i] <= 1000
Solution
Method 1 – Dynamic Programming (Game Theory)
Intuition
This is a classic take-away game. For each number of stones, we check if there is a move (removing a square number) that leaves the opponent in a losing position. If so, the current player can win.
Approach
- Let
dp[i]be true if the current player can win withistones. - For each
i, try all possible square numbersk*k <= i. If there is anydp[i - k*k] == false, thendp[i] = true. - The answer is
dp[n].
Code
C++
class Solution {
public:
bool winnerSquareGame(int n) {
vector<bool> dp(n+1, false);
for (int i = 1; i <= n; ++i) {
for (int k = 1; k*k <= i; ++k) {
if (!dp[i - k*k]) {
dp[i] = true;
break;
}
}
}
return dp[n];
}
};
Go
func winnerSquareGame(n int) bool {
dp := make([]bool, n+1)
for i := 1; i <= n; i++ {
for k := 1; k*k <= i; k++ {
if !dp[i-k*k] {
dp[i] = true
break
}
}
}
return dp[n]
}
Java
class Solution {
public boolean winnerSquareGame(int n) {
boolean[] dp = new boolean[n+1];
for (int i = 1; i <= n; ++i) {
for (int k = 1; k*k <= i; ++k) {
if (!dp[i - k*k]) {
dp[i] = true;
break;
}
}
}
return dp[n];
}
}
Kotlin
class Solution {
fun winnerSquareGame(n: Int): Boolean {
val dp = BooleanArray(n+1)
for (i in 1..n) {
for (k in 1..Math.sqrt(i.toDouble()).toInt()) {
if (!dp[i - k*k]) {
dp[i] = true
break
}
}
}
return dp[n]
}
}
Python
class Solution:
def winnerSquareGame(self, n: int) -> bool:
dp = [False] * (n+1)
for i in range(1, n+1):
k = 1
while k*k <= i:
if not dp[i - k*k]:
dp[i] = True
break
k += 1
return dp[n]
Rust
impl Solution {
pub fn winner_square_game(n: i32) -> bool {
let n = n as usize;
let mut dp = vec![false; n+1];
for i in 1..=n {
let mut k = 1;
while k*k <= i {
if !dp[i - k*k] {
dp[i] = true;
break;
}
k += 1;
}
}
dp[n]
}
}
TypeScript
class Solution {
winnerSquareGame(n: number): boolean {
const dp = Array(n+1).fill(false);
for (let i = 1; i <= n; i++) {
for (let k = 1; k*k <= i; k++) {
if (!dp[i - k*k]) {
dp[i] = true;
break;
}
}
}
return dp[n];
}
}
Complexity
- ⏰ Time complexity:
O(n*sqrt(n))wherenis the number of stones. - 🧺 Space complexity:
O(n)for the DP array.