一种时间复杂度O(logn)的约瑟夫环问题算法

搬运一下自己b站发的文章

约瑟夫环自写算法的思路—1 - 哔哩哔哩 (bilibili.com)一种时间复杂度小于O(n)的约瑟夫环问题算法 - 哔哩哔哩 (bilibili.com)

约瑟夫环问题简介:

已知 n 个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为 1 的人开始报数,数到 m 的那个人出圈;他的下一个人又从 1 开始报数,数到 m 的那个人又出圈;依此规律重复下去,直到剩余最后一个人。

解决思路部分:

直接上python代码,复杂度log(n):

#注:编号是从1开始记的,和力扣上从0开始记的编号不同!
def deadeline(num,d,cold):
    #不能优化的情况,直接用正常方法处理
    if num<=d:
        W=list(range(1,num+1))
        P=[]
        while len(W):
            for i in range(d-1):
                W.append(W.pop(0))#pop(0) 从列表中移除第一个元素并返回该元素。append() 将返回的元素添加到列表的末尾。
            P.append(W[0])
            W.pop(0)
        return(P[cold-1])
    #准备生成递推表,用于确定递推迭代每步操作
    number=num
    list1=[]   #初始化每步对应的余数列表
    list2=[]   #初始化每步对应的n值列表
    while number!=d:             #当n值仍然大于d,则继续计算递推表
        list2.append(number)     #记下这步对应的n值
        list1.append(number%d)   #记下这步对应的余数
        if number%d:
            number-=number%d     #如果不能整除d,减去模d的余数
        else:
            number-=number//d    #如果整除d,减去这个数除d后的数
    #初始化S一开始的赋值
    cold=num-cold+1          #P之后要倒序操作,这里cold也需要倒序
    if cold<=d:              #获得在d个人时的所有死亡顺序
        W=list(range(1,d+1)) #初始化还没死的人
        P=[]                 #用于记录死亡顺序
        while len(W):        #pop(0) 从列表中移除第一个元素并返回该元素。append() 将返回的元素添加到列表的末尾。
            for i in range(d-1):
                W.append(W.pop(0))
            P.append(W[0])
            W.pop(0)
        P=P[::-1]            #P这里可以正序,倒序是因为迭代所有死亡顺序时更方便,这里沿用了该操作
        S=P[cold-1]          #获得S在d个人时对应的编号
    else:
        S=0                  #S在d个人时没有S对应的编号,赋值为0表示为待赋值。
    Q=d   #人数
    le=d  #临时人数
    #开始迭代S的值
    for i in range (len(list1)-1,-1,-1):     #递归结构体
        if list1[i]:   #余数不为0时,多次迁移递归
            for k in range (0,list1[i]):            #余数list1[i]表示添加了多少人,也就要迁移遍历多少次
                if cold<=Q:                         #cold<=Q时,S才被赋值过编号
                    le=list2[i]-list1[i]+k+1        #计算临时人数
                    S=(S+d)%(le)                    #迭代编号
                    if S==0:
                        S=le                        #矫正编号
                Q+=1                                #人数更新
                if cold<=Q and S==0:                #cold==Q时,S需要赋值编号
                    S=d
        else:           #余数为0时,进行倍增递归
            if cold<=Q:                             #cold<=Q时,S才被赋值过编号
                if S%(d-1)!=0:                      #迭代编号
                    S+=int((S-S%(d-1))/(d-1))
                else:
                    S+=int((S)/(d-1)-1)
            Q+=int(Q/(d-1))                         #人数更新
            if cold<=Q and S==0:                    #cold==Q时,S需要赋值编号
                S=3*(Q-cold+1)
    return(S)

for i in range(1,42):    #测试
    print(deadeline(41,3,i),end = " ")

力扣上跑的验证视频:

疑似约瑟夫环问题时间复杂度低于O(n)的算法_哔哩哔哩_bilibili

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值