问题描述略过
最简单的是用队列模拟,没有死的人回到队列末尾,死的人移出队列,直到队列长度为1
例如:
11个人依次叫号,叫到3死
1,2,3,4,5,6,7,8,9,10,11 —>
2,3,4,5,6,7,8,9,10,11,1 —>
3,4,5,6,7,8,9,10,11,1,2
3移出队列
4,5,6,7,8,9,10,11,1,2—>
5,6,7,8,9,10,11,1,2,4—>
6,7,8,9,10,11,1,2,4,5
6移出队列
7,8,9,10,11,1,2,4,5—>
...
直到队列仅剩一人: 7
用队列进行模拟,代码:
def solution(self, n: int, k: int) -> int:
q = []
for i in range(1, n + 1):
q.append(i)
while len(q) != 1:
tmp = 0
while tmp != k - 1:
tmp += 1
q.append(q.pop(0))
q.pop(0)
return q[0]
公式推导:
已知1,2,3,4,5,6,7,8,9,10,11 这11个人中最终胜利者为7号
那么1,2,3,4,5,6,7,8,9,10 这10个人中的最终胜利者是谁?
从11个人往10个人推导,即移除一个人后的队列情况
1,2,3,4,5,6,7,8,9,10,11 —>
4,5,6,7,8,9,10,11,1,2
映射到10个人的情况就是:
1,2,3,4,5,6,7,8,9,10
最终胜利者为4
可以看到11个人时胜利者的索引位置为6
3号被移除后,10个人中胜利者的索引位置为3,胜利者的索引变化为6 - 3 = 3(叫号数)
由此我们可以从只有2个人的时候往回推n个人的情况
即 now = last + 叫号数k
为了防止边界溢出,还需对当前人数取余操作
我们用的是索引,返回结果时不要忘记再加一
代码:
def solution(self, n: int, k: int) -> int:
res = 0
for i in range(2, n + 1):
res = (res + k) % i
return res + 1