LeetCode 292 - Nim Game


[LeetCode]Nim Game | 书影博客
You are playing the following Nim Game with your friend: There is a heap of stones on the table, each time one of you take turns to remove 1 to 3 stones. The one who removes the last stone will be the winner. You will take the first turn to remove the stones.
Both of you are very clever and have optimal strategies for the game. Write a function to determine whether you can win the game given the number of stones in the heap.
For example, if there are 4 stones in the heap, then you will never win the game: no matter 1, 2, or 3 stones you remove, the last stone will always be removed by your friend.
Hint:
If there are 5 stones in the heap, could you figure out a way to remove the stones such that you will always be the winner?


从4开始递推:5、6、7能分别拿掉1、2、3个石头,对方就拿到的是4,就输了,即5、6、7->true。但是当n=8时,无论拿掉多少个石头,对方拿到的都是5/6/7个石头,对方就赢了,故8->false。往后依此递推,9,10,11都可以给对方留下8个,对方就输了。即对于每个n是false,n+1、n+2、n+3都是true,n+4都是false。递推关系满足n被4整除时返回false。
Nim游戏的解题关键是寻找“必胜态”。
根据题设条件:
当n∈[1,3]时,先手必胜。

当n == 4时,无论先手第一轮如何选取,下一轮都会转化为n∈[1,3]的情形,此时先手必负。

当n∈[5,7]时,先手必胜,先手分别通过取走[1,3]颗石头,可将状态转化为n == 4时的情形,此时后手必负。

当n == 8时,无论先手第一轮如何选取,下一轮都会转化为n∈[5,7]的情形,此时先手必负。
......
以此类推,可以得出结论:
当n % 4 != 0时,先手必胜;否则先手必负。
class Solution(object): def canWinNim(self, n): return n % 4 > 0
https://segmentfault.com/a/1190000003884660
策略在于,因为每个人都取不到4个,假设自己后走,要保证每轮自己和对方取得数量的和是4,这样就能确保每轮完后都有4的倍数个石头被取走。这样,如果我们先走的话,先把n除4的余数个石头拿走,这样不管怎样,到最后都会留4个下来,对方取1个你就取3个,对方取2个你就取2个,就必赢了。
https://leetcode.com/discuss/63725/theorem-all-4s-shall-be-false

Theorem: The first one who got the number that is multiple of 4 (i.e. n % 4 == 0) will lost, otherwise he/she will win.
Proof:
  1. the base case: when n = 4, as suggested by the hint from the problem, no matter which number that that first player, the second player would always be able to pick the remaining number.
  2. For 1* 4 < n < 2 * 4, (n = 5, 6, 7), the first player can reduce the initial number into 4 accordingly, which will leave the death number 4 to the second player. i.e. The numbers 5, 6, 7 are winning numbers for any player who got it first.
  3. Now to the beginning of the next cycle, n = 8, no matter which number that the first player picks, it would always leave the winning numbers (5, 6, 7) to the second player. Therefore, 8 % 4 == 0, again is a death number.
  4. Following the second case, for numbers between (2*4 = 8) and (3*4=12), which are 9, 10, 11, are winning numbers for the first player again, because the first player can always reduce the number into the death number 8.
If you are familiar with math induction, this problem can be proved by natural induction.
Base case: n = 4, we can show that for taking 1, 2, or 3, you will always lose.
Induction case: suppose for n = 4K, you will lose. For 4 (K + 1), you have 4K + 4, which is 4 more than 4K. For all the possible choice (1, 2, 3), your enemy can take 3, 2, 1 so you must take 4K, which is losing.
Thus, for all 4K (K is natural number) cases, you will lose.
public boolean canWinNim(int n) { return (n & 3) != 0; }
https://leetcode.com/discuss/72624/my-solution-with-java
public boolean canWinNim(int n) { return n>>2<<2!=n; }
X.  DP
https://leetcode.com/problems/nim-game/discuss/73845/Two-Java-Solution.
I can explain it to you. When there is n stones you have three choices: A)pick one and leave (n-1) to your friend. B)pick two and leave (n-2). C)pick three and leave (n-3). In situation A), your friend have three choices too, to leave (n-2),(n-3),(n-4) to you. To win, you need make sure all the three possible situations are true. Similar with situation B and C. Because you can choose from AB or C, then you need to make sure A or B or C is true. That is dp[i] = (dp[i - 2] && dp[i - 3] && dp[i - 4])|| (dp[i - 3] && dp[i - 4] && dp[i - 5])|| (dp[i - 4] && dp[i - 5] && dp[i - 6]). Must have a three consecutive true to win between n-2 and n-6. Other wise lose.
DP : Line 7: java.lang.OutOfMemoryError: Java heap space
public boolean canWinNim(int n) {
    if(n <= 0)
        throw new IllegalArgumentException();
    if(n < 4)
        return true;
    boolean[] res = new boolean[n + 1];
    res[0] = true;
    res[1] = true;
    res[2] = true;
    res[3] = true;
    for(int i = 4 ; i <= n ; i++)
        res[i] = !(res[i - 1] && res[i - 2] && res[i - 3]);
    return res[n];
}

I came up with a DP solution that uses O(n) time and O(1) space, but still the online Judge complained about time limit exceeded. Is the Online Judge only looking for the constant time solution?
public class Solution {
    public boolean canWinNim(int n) {
        boolean[] results = {true,true,true,false};
        for (int i=4; i<n; i++){
            results[i%4] = !(results[(i-1)%4]&&results[(i-2)%4]&&results[(i-3)%4]);
        }
        return results[(n-1)%4];
    }
}
It should be: (!res[i - 1]) || (!res[i - 2]) || (!res[i - 3]) which is equivalent to !(res[i - 1] && res[i - 2] && res[i - 3])

    private int count = 1;
    public boolean canWinNim(int n) {
        if(n<=3){
            if(count%2!=0)
                return true;
            else
                return false;
        }
        else {
            count++;
            return canWinNim(n - 1) || canWinNim(n - 2) || canWinNim(n - 3);
        }
    }
https://leetcode.com/discuss/72322/interviewer-prefer-candidates-burte-force-instead-method
public boolean canWinNim(int n) { if(n>=134882061){//I have no any other ways,please forgive my unchastity(无节操)! return n%4 != 0; } int[] array=new int[n+1]; return dfs(n, array); } public boolean dfs(int n,int[] array){ if(array[n]!=0){ return array[n]==1?true:false; } if(n<=3){ array[n]=1; return true; }else{ for(int i=1;i<=3;i++){ if(!dfs(n-i,array)){ array[n-i]=-1; array[n]=1; return true; } } array[n]=-1; return false; } }
Read full article from [LeetCode]Nim Game | 书影博客

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts