原题如下:
思路:
这是一道简单的题,难点在于考虑题中“都是聪明人,聪明人如何移动”这个地方,因为我们先手,这时候分两种情况:n能否被4整除。
1、n不能被4整除,例如1,2,3,5,6,7这种,我们可以控制我们每次取之后的结果都是4的倍数,这样无论对面拿几个,他一定拿不到最后一个,这相当于我们保证他赢不了。
2、n可以被4整除,这时候我们一定输,因为这时候我们拿了以后相当于让对面可以控制他每次取之后的结果都是4的倍数,我们就赢不了。
这是直观的理解,证明可以用数学归纳法,这里笔者略去。
因此这个问题可以判断是否是4的倍数,是则返回False,否则返回True。
代码:
class Solution:
def canWinNim(self, n: int) -> bool:
if n%4==0:
return False
return True
划重点!
这里有一个用位运算代替模运算的技巧,
在a%b这种情形下,如果b是2的倍数,a%b=a&(b-1)。
下面是其正确性的解释:
我们以数字4为例,
(1)因为是模运算,二进制中>=4的位置部分可以直接抹去,
因为他们分别代表数字4、8、16、32...,都能整除4,这时候我们通过&00...00xx实现。
(2)对于后面2位,我们保留下来,就是我们求的余数,通过&11实现。
因此整体相当于&00..0011,也就是&n-1。
推广到所有2的倍数,对其进行模运算时,其二进制中1以及之前的位置都直接抹去,
1之后的位置保留,结果即为余数,即为a%b=a&(b-1)。
特别有用的一点是,当b为2时,公式为
a%2=a&1
因为位运算比取模快得多,在判断数字奇偶的情况时可以用a&1来判断。