一道类似Joseph环的智力题
这是一个在面试中被问到的问题,其实细想起来很简单。但当时只给了两分钟,没能直接给出解决方案。
问题描述
有156个海盗在一个岛上,他们决定选一个人出来做老大,由于人这么多,选谁当老大一直没有选好,于是他们想出来一个办法,把这156个人从1到156编号,然后按1, 2, 1, 2, …报数,报到1的退出选举,剩下来的人继续重新报数,然后把‘1’的人踢出局,最后剩下来的就是老大。那么请问,谁是老大?
解题思路
这个问题有点像经典的Joseph环,但其实要比Joseph环容易。由于每次是报‘1’的人出局,所以我们可以用x % 2 == 0来作为判断条件。于是程序可以写成下面这样:
(python)
def calc_out_2(num):
nlist = range(1, num)
cnt = 1
while len(nlist) != 1:
nlist = [x / 2 for x in nlist if x % 2 == 0]
cnt *= 2
return cnt
calc_out_2(156)
装B一下,用一下函数式编程,可以写成这样:
def calc_out_3(num):
nlist = range(1, num)
cnt = 1
while len(nlist) != 1:
nlist = map(lambda x:x/2, filter(lambda x:x%2 == 0, nlist))
cnt *= 2
return cnt
calc_out_1(156)
再仔细的分析一下,由于每次都是‘1’出局,所以定义F(n)为n个海盗选老大的函数。
F(2) = 2
F(3) = 2
F(4) = 4
F(5) = 4
F(6) = 4
F(7) = 4
F(8) = 8
F(9) = 8
…
看出来规律了吧:
F(n) = max(2^x) if 2^x < n
重写Python代码如下:
import math as m
log = m.log
def calc_out_1(num):
return pow(2, int(log(num)/log(2)))
calc_out_1(156)