题目来源:https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/
0,1,,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。
示例 1:
输入: n = 5, m = 3
输出: 3限制:
1 <= n <= 10^5
1 <= m <= 10^6
思路:
由于n和m的范围都很大,如果用循环链表来做会超时。这实际上是一个约瑟夫问题:
N个人围成一圈,第一个人从1开始报数,报M的将被杀掉,下一个人接着从1开始报。如此反复,最后剩下一个,求最后的胜利者。
约瑟夫问题是有数学解的,设 表示n个数、不断删除第m个数、最后剩下的数字,则有:
推导过程:
Q1:假设已经知道n=11、m=3时,最后胜利的人的下标为6,那么n=10、m=3时,最后胜利的人的下标?
A1:第一次删去第m个人后,从第m+1个人开始重新标号,所以所有人的标号都减少了m(取mod来满足循环)。
Q2:假设已经知道n=10、m=3时,最后胜利的人的下标为3,那么n=11、m=3时,最后胜利的人的下标?
A2:第一个问题的逆过程,所以所有人的标号都增加了m(同样取mod来满足循环)
Q3:扩展到任意情况,人数为n、删除报到m的那个人,那么最后胜利的人的下标是怎么移动的?
A3:从n=2开始逐层递推,f(3)=(f(2)+m)%3,f(4)=(f(3)+m)%4,f(5)=(f(4)+m)%5......f(n)=(f(n-1)+m)%n
代码:
class Solution(object):
def lastRemaining(self, n, m):
"""
:type n: int
:type m: int
:rtype: int
"""
last = 0
for i in range(2, n+1):
last = (last + m) % i
return last
参考:
https://blog.csdn.net/u011500062/article/details/72855826