约瑟夫环问题(Josephus problem)

问题:0,1,…,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求这个圆圈里剩下的最后一个数字。

注意到,一开始有 n 个人,报到 m 的人出局后,如果我们从刚才出局的那人的下一位开始重新从 1 开始编号,原问题就转化为了一个 n–1 人的问题。如下表所示:

原始编号(i) 第一个人出局后的编号(j)
m 0
m+1 1
m+2 2
m-2 n-2 (n为出局前的总人数)
m-1 OUT

可以看出老编号i和新编号j的关系为:i = (j+m) % n,于是总结递推公式:

f(n) = (f(n-1) + m) % n (n > 1),其中f(n)为当场上还有n个人时在场的人的编号。
当最后只剩下一个人的时候,这个人的编号只能是0,即f(1)=0,现在根据上面的公式反推,推导出当n个人在场时这个最后幸存者的编号。例如:f(2)=(f(1)+m) % 2,所以range范围从2开始,执行n-1次,也就是range(2, n+1)

1
2
3
4
5
6
7
8
def LastRemaining_Solution(self, n, m):
# write code here
if n<=0 or m<=0:
return -1
last_num = 0
for i in range(2, n+1):
last_num = (last_num+m) % i
return last_num