JZ46 孩子们的游戏(圆圈中最后剩下的数)

描述

每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。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),如果这个n=2^k,则有J(2^k)=1

人数不为2的幂次方的时候,J(2^k+t)=2t+1

(2)另外一种情况,q不等于2的时候

可以得到规律:J_q(n+1)=\frac{(J_q(n)+q)}{(n+1)}

还有比如说有九个人(n=9),假设q=4,此时首先去除的就是3,那么换了新的下标索引后:

那么假设新的下标索引为New,旧的下标索引为Old。

则它们两个之间的关系是:Old=(New+q) % n

用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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值