Welcome to Subscribe On Youtube
1908. Game of Nim
Description
Alice and Bob take turns playing a game with Alice starting first.
In this game, there are n
piles of stones. On each player's turn, the player should remove any positive number of stones from a non-empty pile of his or her choice. The first player who cannot make a move loses, and the other player wins.
Given an integer array piles
, where piles[i]
is the number of stones in the ith
pile, return true
if Alice wins, or false
if Bob wins.
Both Alice and Bob play optimally.
Example 1:
Input: piles = [1] Output: true Explanation: There is only one possible scenario: - On the first turn, Alice removes one stone from the first pile. piles = [0]. - On the second turn, there are no stones left for Bob to remove. Alice wins.
Example 2:
Input: piles = [1,1] Output: false Explanation: It can be proven that Bob will always win. One possible scenario is: - On the first turn, Alice removes one stone from the first pile. piles = [0,1]. - On the second turn, Bob removes one stone from the second pile. piles = [0,0]. - On the third turn, there are no stones left for Alice to remove. Bob wins.
Example 3:
Input: piles = [1,2,3] Output: false Explanation: It can be proven that Bob will always win. One possible scenario is: - On the first turn, Alice removes three stones from the third pile. piles = [1,2,0]. - On the second turn, Bob removes one stone from the second pile. piles = [1,1,0]. - On the third turn, Alice removes one stone from the first pile. piles = [0,1,0]. - On the fourth turn, Bob removes one stone from the second pile. piles = [0,0,0]. - On the fifth turn, there are no stones left for Alice to remove. Bob wins.
Constraints:
n == piles.length
1 <= n <= 7
1 <= piles[i] <= 7
Follow-up: Could you find a linear time solution? Although the linear time solution may be beyond the scope of an interview, it could be interesting to know.
Solutions
-
class Solution { private Map<Integer, Boolean> memo = new HashMap<>(); private int[] p = new int[8]; public Solution() { p[0] = 1; for (int i = 1; i < 8; ++i) { p[i] = p[i - 1] * 8; } } public boolean nimGame(int[] piles) { return dfs(piles); } private boolean dfs(int[] piles) { int st = f(piles); if (memo.containsKey(st)) { return memo.get(st); } for (int i = 0; i < piles.length; ++i) { for (int j = 1; j <= piles[i]; ++j) { piles[i] -= j; if (!dfs(piles)) { piles[i] += j; memo.put(st, true); return true; } piles[i] += j; } } memo.put(st, false); return false; } private int f(int[] piles) { int st = 0; for (int i = 0; i < piles.length; ++i) { st += piles[i] * p[i]; } return st; } }
-
class Solution { public: bool nimGame(vector<int>& piles) { unordered_map<int, int> memo; int p[8] = {1}; for (int i = 1; i < 8; ++i) { p[i] = p[i - 1] * 8; } auto f = [&](vector<int>& piles) { int st = 0; for (int i = 0; i < piles.size(); ++i) { st += piles[i] * p[i]; } return st; }; function<bool(vector<int>&)> dfs = [&](vector<int>& piles) { int st = f(piles); if (memo.count(st)) { return memo[st]; } for (int i = 0; i < piles.size(); ++i) { for (int j = 1; j <= piles[i]; ++j) { piles[i] -= j; if (!dfs(piles)) { piles[i] += j; return memo[st] = true; } piles[i] += j; } } return memo[st] = false; }; return dfs(piles); } };
-
class Solution: def nimGame(self, piles: List[int]) -> bool: @cache def dfs(st): lst = list(st) for i, x in enumerate(lst): for j in range(1, x + 1): lst[i] -= j if not dfs(tuple(lst)): return True lst[i] += j return False return dfs(tuple(piles))
-
func nimGame(piles []int) bool { memo := map[int]bool{} p := make([]int, 8) p[0] = 1 for i := 1; i < 8; i++ { p[i] = p[i-1] * 8 } f := func(piles []int) int { st := 0 for i, x := range piles { st += x * p[i] } return st } var dfs func(piles []int) bool dfs = func(piles []int) bool { st := f(piles) if v, ok := memo[st]; ok { return v } for i, x := range piles { for j := 1; j <= x; j++ { piles[i] -= j if !dfs(piles) { piles[i] += j memo[st] = true return true } piles[i] += j } } memo[st] = false return false } return dfs(piles) }
-
function nimGame(piles: number[]): boolean { const p: number[] = Array(8).fill(1); for (let i = 1; i < 8; ++i) { p[i] = p[i - 1] * 8; } const f = (piles: number[]): number => { let st = 0; for (let i = 0; i < piles.length; ++i) { st += piles[i] * p[i]; } return st; }; const memo: Map<number, boolean> = new Map(); const dfs = (piles: number[]): boolean => { const st = f(piles); if (memo.has(st)) { return memo.get(st)!; } for (let i = 0; i < piles.length; ++i) { for (let j = 1; j <= piles[i]; ++j) { piles[i] -= j; if (!dfs(piles)) { piles[i] += j; memo.set(st, true); return true; } piles[i] += j; } } memo.set(st, false); return false; }; return dfs(piles); }