描述
每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)
如果没有小朋友,请返回-1
题目给出的示例是五个小朋友,指定数为m,那么我们假设五个小朋友最开始的编号为0,1,2,3,4。因为每次喊到m-1的小朋友出列,所以增加了Index那栏好理解一些,经过四轮的出列,剩下的小朋友就是3号。
整个游戏是一个约瑟夫环问题。关于问题背景可以了解:https://blog.csdn.net/tingyun_say/article/details/52343897
整个问题可以总结为总共有n个人(编号为0~n-1),最后只留下一个人。
规则是提前指定一个数为m,按顺序报数,每次报数m-1的人将会出列,剩下的人从出列的下一个人重新报数,报到m-1的人继续出列,直到剩下最后一个人。
这里试着理解下博主的思路:
(1)首先看一下特例,也就是q等于2的时候。(在博主的文章里有详细的说明)
①人数为2的幂次方的时候,剩余的都是1号,所以假设约瑟夫环的函数设为J(n),如果这个,则有
。
②人数不为2的幂次方的时候,。
(2)另外一种情况,q不等于2的时候。
可以得到规律:
还有比如说有九个人(n=9),假设q=4,此时首先去除的就是3,那么换了新的下标索引后:
那么假设新的下标索引为New,旧的下标索引为Old。
则它们两个之间的关系是:
用Array2来举例,Old为2,New为7,则(7+4)%9=2。
以上是关于约瑟夫环问题的一些规律。
接下来是讨论组的解决方法:
#方法1:使用list模拟循环链表,用cur作为指向list的下标位置。
#当cur移到list末尾直接指向list头部,当删除一个数后list的长度和cur的值相等则cur指向0
class Solution:
def LastRemaining_Solution(self, n, m):
# write code here
if n < 1 or m < 1:
return
childNum = list(range(n))
print(childNum)
cur = 0 # 指向list的指针
while len(childNum) > 1:
for i in range(1,m):
cur += 1
# 当指针移到list的末尾,则将指针移到list的头
if cur == len(childNum):
cur = 0
# 删除一个数,此时由于删除之后list的下标随之变化
# cur指向的便是原数组中的下一个数字,此时cur不需要移动
childNum.remove(childNum[cur])
if cur == len(childNum): # list的长度和cur的值相等则cur指向0
cur = 0
return childNum
#方法2:动态规划
class Solution:
def LastRemaining_Solution(self, n, m):
# write code here
if n < 1 or m < 1:
return -1
last = 0
for i in range(2, n+1):
last = (last+m)%i
return last