一行代码就能解决的算法题
目录
第 292 题「Nim 游戏」
题目
你和你的朋友面前有一堆石子,你们轮流拿,一次至少拿一颗,最多拿三颗,谁拿走最后一颗石子谁获胜
假设你们都很聪明,由你第一个开始拿,请你写一个算法,输入一个正整数 n
,返回你是否能赢(true 或 false)。
反着思考
- 如果我能赢,那么最后轮到我取石子的时候必须要剩下 1~3 颗石子,这样我才能一把拿完
- 显然,如果对手拿的时候只剩 4 颗石子,那么无论他怎么拿,总会剩下 1~3 颗石子,我就能赢。
- 如何逼迫对手面对 4 颗石子呢?
- 让我选择的时候还有 5~7 颗石子,这样的话我就有把握让对方不得不面对 4 颗石子。
- 如何营造 5~7 颗石子的局面呢?让对手面对 8 颗石子,无论他怎么拿,都会给我剩下 5~7 颗,我就能赢。
- 这样一直循环下去,我们发现只要踩到 4 的倍数,就落入了圈套,永远逃不出 4 的倍数,而且一定会输
- 如何营造 5~7 颗石子的局面呢?让对手面对 8 颗石子,无论他怎么拿,都会给我剩下 5~7 颗,我就能赢。
- 让我选择的时候还有 5~7 颗石子,这样的话我就有把握让对方不得不面对 4 颗石子。
- 如何逼迫对手面对 4 颗石子呢?
- 显然,如果对手拿的时候只剩 4 颗石子,那么无论他怎么拿,总会剩下 1~3 颗石子,我就能赢。
代码
var canWinNim = function(n) {
// 如果上来就踩到 4 的倍数,那就认输吧
// 否则,可以把对方控制在 4 的倍数,必胜
return n % 4 !== 0;
}
第 877 题「石子游戏」
题目
你和你的朋友面前有一排石头堆
- 用一个数组
piles
表示,piles[i]
表示第i
堆石子有多少个 - 你们轮流拿石头,一次拿一堆,但是只能拿走最左边或者最右边的石头堆。
- 所有石头被拿完后,谁拥有的石头多,谁获胜。
- 一是石头总共有偶数堆,石子的 总数 是 奇数 ,所以没有平局
假设你们都很聪明,由你第一个开始拿,请你写一个算法,输入一个数组 piles
,返回你是否能赢(true 或 false)。
举个例子,piles=[2, 1, 9, 5]
- 你先拿,可以拿 2 或者 5,你选择 2。
piles=[1, 9, 5]
,轮到对手,可以拿 1 或 5,他选择 5。piles=[1, 9]
轮到你拿,你拿 9。- 最后,你的对手只能拿 1 了。
- 这样下来,你总共拥有
2 + 9 = 11
颗石头,对手有5 + 1 = 6
颗石头,你是可以赢的,所以算法应该返回 true。
结论:==只要你足够聪明,你是必胜无疑的,因为你是先手。==
var stoneGame = function(piles) {
return true;
}
第 319 题「灯泡开关」
有 n
盏电灯,最开始时都是关着的。现在要进行 n
轮操作:
- 第 1 轮操作是把每一盏电灯的开关按一下(全部打开)。
- 第 2 轮操作是把每两盏灯的开关按一下(就是按第 2,4,6… 盏灯的开关,它们被关闭)。
- 第 3 轮操作是把每三盏灯的开关按一下(就是按第 3,6,9… 盏灯的开关,有的被关闭,比如 3,有的被打开,比如 6)
- …
- 如此往复,直到第
n
轮,即只按一下第n
盏灯的开关。
现在给你输入一个正整数 n
代表电灯的个数,问你经过 n
轮操作后,这些电灯有多少盏是亮的?
思考
首先,因为电灯一开始都是关闭的,所以某一盏灯最后如果是点亮的,必然要被按奇数次开关。
- 我们假设只有 6 盏灯,而且我们只看第 6 盏灯。
- 需要进行 6 轮操作对吧,请问对于第 6 盏灯,会被按下几次开关呢?
- 这不难得出,第 1 轮会被按,第 2 轮,第 3 轮,第 6 轮都会被按。
- 为什么第 1、2、3、6 轮会被按呢?因为
6=1*6=2*3
。- 一般情况下,因子都是成对出现的,也就是说开关被按的次数一般是偶数次。
- 但是有特殊情况,比如说总共有 16 盏灯,那么第 16 盏灯会被按几次?
16 = 1*16 = 2*8 = 4*4
其中因子 4 重复出现,所以第 16 盏灯会被按 5 次,奇数次。- 就假设现在总共有 16 盏灯,我们求 16 的平方根,等于 4,这就说明最后会有 4 盏灯亮着,它们分别是第
1*1=1
盏、第2*2=4
盏、第3*3=9
盏和第4*4=16
盏。
- 就假设现在总共有 16 盏灯,我们求 16 的平方根,等于 4,这就说明最后会有 4 盏灯亮着,它们分别是第
- 为什么第 1、2、3、6 轮会被按呢?因为
- 这不难得出,第 1 轮会被按,第 2 轮,第 3 轮,第 6 轮都会被按。
- 需要进行 6 轮操作对吧,请问对于第 6 盏灯,会被按下几次开关呢?
代码
var bulbSwitch = function(n) {
return Math.floor(Math.sqrt(n));
};