圆圈中最后剩下的数(约瑟夫环问题)

圆圈中最后剩下的数(约瑟夫环问题)

描述

每年六一儿童节,牛客都会准备一些小礼物和小游戏去看望孤儿院的孩子们。其中,有个游戏是这样的:首先,让 n 个小朋友们围成一个大圈,小朋友们的编号是0~n-1。然后,随机指定一个数 m ,让编号为0的小朋友开始报数。每次喊到 m-1 的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0… m-1报数…这样下去…直到剩下最后一个小朋友,可以不用表演,并且拿到牛客礼品,请你试着想下,哪个小朋友会得到这份礼品呢?
在这里插入图片描述
数据范围:1<= n <= 5000, 1<= m <= 10000
要求:空间复杂度 O(1),时间复杂度 O(n)

法一:通过链表或数组模拟
思路

通过数组来模拟循环列表,初始情况下给每个小朋友编号0~n-1,再用一个变量count来记录已经报数的个数,若count==m,则将该报数的小朋友编号记为-1,表示已经出局,不断循环,直到还剩下唯一一个编号不是-1的,返回该编号即可。 该方法虽然容易理解,却容易超时
时间复杂度:O(N^2)
空间复杂度:O(N),申请一个数组标记每个小孩子是否退圈

# -*- coding:utf-8 -*-
class Solution:
    def LastRemaining_Solution(self, n, m):
        array = list(range(n))
        i = 0
        count = 0 	# 记录已经报数的
        while array.count(-1) < n-1: # 若只剩一个小朋友,则跳出
            if array[i] != -1:
                count = count+1
                if count==m:
                    array[i] =-1
                    count = 0
            i = i+1
            if i==n: # 数组模拟循环列表
                i = i%n
        # 遍历输出答案
        for i in array:
            if i!=-1:
                return i
法二: 约瑟夫问题递推公式
思路: 利用约瑟夫问题的递推公式 f(n,m) = ( f(n-1,m) +m)%n )

公式递推:
令f(n,m)表示最后一个人的下标。
1.假设有n个人,报数m, 从0 开始报数,易知出圈的人下标为 m-1。
2.m-1 出圈后,我们对剩余人重新编号 即 第m个人下标为0,第m+1 下标为1 …以此编号。 那么重新编号之后,最后一个人的下标为f(n-1,m)
问题1: 在重新编号之后的f(n-1,m) 与 重新编号之前的f(n,m)有什么关系?
重新编号之前 m, m+1,m+2,…
重新编号之后 0 ,1 ,2,…
可知 (新编号+m)%n = 旧编号
f(n,m) = (f(n-1,m)+m) %n;
递归写法复杂度分析:
时间复杂度: O(N)
空间复杂度: O(N)

class Solution:
    def LastRemaining_Solution(self, n, m):
        if n<=0:
            return -1
        return (self.LastRemaining_Solution(n-1,m)+m)%n
迭代方式:
class Solution:
    def LastRemaining_Solution(self, n, m):
        if n<=0:
            return -1
        f = 0
        for i in range(2,n+1):
            f = (f+m)%i
        return f
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值