一次失败的刷题经历:[LeetCode]292之尼姆游戏(Nim Game)

最近闲来无事刷LeetCode,发现这道题的Accept Rate还是挺高的,尝试着做了一下,结果悲剧了,把过程写下来,希望能长点记性。该题的描述翻译成中文如下:

你正在和你的朋友玩尼姆游戏(Nim Game): 桌子上有一堆石块,你和你的朋友轮流去拿这些石块,每次只能拿1块、2块或者3块。在石块被拿光前,最后一次拿到石块的人获胜。你将首先去拿这些石块。 你和你的朋友都非常聪明,并且拥有应对该游戏的最佳策略。写一个函数来决定在给定石块数量的情况下,你是否能够获胜。比如:如果桌子上有4块石块,那么你将不可能获胜:不管你先拿出1块、2块还是3块石头,最后一次拿光石块的永远都会是你的朋友。(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看了一下:

Hint:

  1. 如果桌子上有5块石头,你能找到确保你会获胜的拿石块的方法吗?(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?)

第一反应自然是递归了,于是写下了下面的code:

 1  public static boolean canWinNim_recurion(int stoneCount) {
 2         if(stoneCount<=0) {
 3             System.out.println("illegal input");
 4             return false;
 5         }
 6         /* you will win */
 7         if((0<stoneCount)&&(stoneCount<4)) {
 8             return true;
 9         }
10
11         return !(canWinNim_recurion(stoneCount-1)&&canWinNim_recurion(stoneCount-2)&&canWinNim_recurion(stoneCount-3));
12     }

提交后给出StackOverflowError,自己在本机上用大数(1348820612)试验了一下也是StackOverflowError。原因自然是递归太深了。于是又写下了下面的code:

 1  public static boolean canWinNim(int stoneCount) {
 2         if(stoneCount<=0) {
 3             System.out.println("illegal input");
 4             return false;
 5         }
 6
 7         boolean[] canWinArray = new boolean[stoneCount];
 8         for(int i=1;i<=stoneCount;i++) {
 9             if(i==1||i==2||i==3) {
10                 canWinArray[i-1] = true;
11                 continue;
12             }
13             canWinArray[i-1] = !(canWinArray[i-2]&&canWinArray[i-3]&&canWinArray[i-4]);
14         }
15         return canWinArray[stoneCount-1];
16     }

这一次的思路是把递归改成循环,而且为了简单起见,是自底向上的循环。没记错的话这其实是一个DP的解法。但是提交后,给出Memory Limit Exceeded错误,那就是O(n)的空间复杂度不符合要求了。于是给出了下面的空间复杂度为常量的code:

 1  public boolean canWinNim2(int stoneCount) {
 2         boolean canWin = false;
 3
 4         if(stoneCount<=0) {
 5             System.out.println("illegal input");
 6             return false;
 7         }
 8
 9         /* only need a boolean array of length 3 ? */
10         //boolean[] canWinArray = new boolean[stoneCount];
11         boolean[] last3CanWinArray = new boolean[3];
12
13         for(int i=1;i<=stoneCount;i++) {
14             if(i==1||i==2||i==3) {
15                 last3CanWinArray[i-1] = true;
16                 canWin = true;
17                 continue;
18             }
19             canWin = !(last3CanWinArray[0]&&last3CanWinArray[1]&&last3CanWinArray[2]);
20             // update the array
21             last3CanWinArray[0] = last3CanWinArray[1]; // the index cannot be i-2 i-3 etc.
22             last3CanWinArray[1] = last3CanWinArray[2];
23             last3CanWinArray[2] = canWin;
24         }
25         return canWin;
26     }

但是提交后提示Time Limit Exceeded。这个算法的时间复杂度为O(n),难道还不符合要求吗? 百思不得其解,google了一下,发现这道题的考察意图在找规律而不在写code。然后终于找到了规律:被4整除的石头数,都不可能赢;其他数则能赢。那么代码就太简单了,一行就搞定:

1  public boolean canWinNim_brainteaser(int stoneCount) {
2         return stoneCount%4!=0;
3     }

提交后提示成功,至此算是把这题刷完了。

失败总结:其实,在这道题的描述和Hint后头,有一个tag标签,点开可以看到清清楚楚地写着:brainteaser。也就是脑筋急转弯。而我还老是往DP方面去想,结果自然是悲剧了。刷这道题给了我一个教训:就像高中时刷题一样,对待算法题一定要注意审题,不漏掉题目给出的每一个细节,重视每一个给出的提示,并按照提示给出的方向去思考。

时间: 2024-10-10 02:38:52

一次失败的刷题经历:[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 th

[LeetCode]-292. Nim Game(Easy)(C + 尼姆游戏)

292. Nim Game My Submissions Question Editorial Solution Total Accepted: 67907 Total Submissions: 128306 Difficulty: Easy 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

算法刷题记录

ACWING acwing 528. 奶酪 解题记录 acwing 471. 棋盘 解题记录 acwing 95 费解的开关 解题记录 dfs的几个基础示例 acwin 91~94 LEETCODE 刷题记录与资料 LEETCODE 1031. 两个非重叠子数组的最大和 dfs的几个基础示例 leetcode 刷题进展 leetcode 算法分类 原文地址:https://www.cnblogs.com/itdef/p/10854320.html

在vscode中配置LeetCode插件,从此愉快地刷题

大家好,今早在B站看到up主的vscode里藏了leetcode插件,这才知道原来还有这款神器.但是没想到在用的时候遇到了一些麻烦,花了一点时间才解决.所以写这篇文章除了给大家安利这个好用的插件之外,也是为了帮助更多的同学避免踩坑. 简介vscode vscode在工业界鼎鼎大名,被誉为微软少有的拿得出手的精品(逃).原本是不想过多赘述的,但是鉴于许多粉丝还是正在上学的萌新,所以花点笔墨简单介绍一下. vscode是微软开发的编辑器,严格说起来它并不是一个IDE,只是一个编辑器.但是由于它支持嵌

【leetcode刷题笔记】Sum Root to Leaf Numbers

Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number. An example is the root-to-leaf path 1->2->3 which represents the number 123. Find the total sum of all root-to-leaf numbers. For example, 1 / 2 3 T

leetcode 刷题之路 63 Binary Tree Zigzag Level Order Traversal

Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alternate between). For example: Given binary tree {3,9,20,#,#,15,7}, 3 / 9 20 / 15 7 return its zig

leetcode 刷题之路 64 Construct Binary Tree from Inorder and Postorder Traversal

Given inorder and postorder traversal of a tree, construct the binary tree. Note: You may assume that duplicates do not exist in the tree. 给出二叉树的中序遍历和后序遍历结果,恢复出二叉树. 后序遍历序列的最后一个元素值是二叉树的根节点的值,查找该元素在中序遍历序列中的位置mid,根据中序遍历和后序遍历性质,有: 位置mid以前的序列部分为二叉树根节点左子树中

【leetcode刷题笔记】Longest Consecutive Sequence

Given an unsorted array of integers, find the length of the longest consecutive elements sequence. For example,Given [100, 4, 200, 1, 3, 2],The longest consecutive elements sequence is [1, 2, 3, 4]. Return its length: 4. Your algorithm should run in

【leetcode刷题笔记】Remove Duplicates from Sorted Array II

Follow up for "Remove Duplicates":What if duplicates are allowed at most twice? For example,Given sorted array A = [1,1,1,2,2,3], Your function should return length = 5, and A is now [1,1,2,2,3]. 题解: 设置两个变量:右边kepler和前向游标forward.如果当前kepeler所指的元素和