Offer 62. 约瑟环(规律问题-递归-中等)

Offer 62. 圆圈中最后剩下的数字

思路1:
    ⭐ 创建一个下标为 0~n-1的数组      | 当n=5时     nums = [1 1 1 1 1] 代表下标为i的数是否已经被删除
    ⭐ 通过不断(外层设置一个循环)进行遍历列表 + 设置一个计算器(当nums中的元素为0则不计数)   每次到达3就将对应nums中的元素置零
    ⭐ (外层循环)停止条件:记录删除的元素个数  当删除的元素为n-1时,返回列表中对应1的下标。
    超时
复杂度:时间复杂度O(n^2)   空间复杂度O(n)
存在问题: 题目中给定范围1 <= n <= 10^5   n^2 = 10^10 这么高的复杂度  结果造成了超时   故该方法在本题中并不适用。所以考虑一下是否有规律性的结论存在
PS:返回列表nums元素x的下标  nums.index(x)       如果x在nums中有多个  则返回的是找到的第一个的下标
def lastRemaininng1(n, m):
    count = 0
    delnum = 0
    nums = [1] * n
    while delnum < n - 1:
        for i in range(n):
            if nums[i] == 0:
                continue
            count += 1
            if count == m:
                delnum += 1
                nums[i] = 0
                count = 0
    return nums.index(1)

 

思路2:该思路是借助力扣COOLUCAS的想法加上一些自己的想法。
    问题:该问题的约瑟环问题  最开始的问题是 n个人围成一圈,第一个人从1开始报数,报m的将被杀掉,下一个人接着从1开始报。如此反复,最后剩下一个,求最后的胜利者。 
    分析:
         我们可以把问题转化为求最后求胜利者下标的问题(只关心下标)。
    ⭐ 首先定义一下f(n,m)、f(n-1,m)……f(1,m) 
        f(n,m)指的是下标为 0,1,2,……,n-1 n个元素([A,B,C,……,Z])的约瑟环 删除第m个数字,最后剩下胜利者的下标
        f(n-1,m)指的是下标为0,1,2,……,n-2 n-1个元素([A,B,C,……,Y])的约瑟环 删除第m个数字,最后剩下胜利者的下标
                            ………………
        f(1,m)指的是下标为0的 1个元素([A])的约瑟环 删除第m个数字,最后剩下胜利者的下标
    ⭐ 下面我们举例分析一下求解F(8,3)的过程
      下标     0   1   2   3   4   5   6   7 
              A   B   C   D   E   F   G   H     第一轮 C(下标2) 被杀     
              D   E   F   G   H   A   B         第二轮 F(下标5) 被杀
              G   H   A   B   D   E             第三轮 A(下标0) 被杀
              B   D   E   G   H                 第四轮 E(下标4) 被杀
              G   H   B   D                     第五轮 B(下标1) 被杀
              D   G   H                         第六轮 H(下标7) 被杀
              D   G                             第七轮 D(下标3) 被杀
              G                                 第八轮 G(下标6) 获胜
   再分析一下求解F(7,3)的过程   如果一开始其内的内容为  D   E   F   G   H   A   B (求下标 与其内容无关)
      下标     0   1   2   3   4   5   6  
              D   E   F   G   H   A   B         第一轮 F(下标5) 被杀
              G   H   A   B   D   E             第二轮 A(下标0) 被杀
              B   D   E   G   H                 第三轮 E(下标4) 被杀
              G   H   B   D                     第四轮 B(下标1) 被杀
              D   G   H                         第五轮 H(下标7) 被杀
              D   G                             第六轮 D(下标3) 被杀
              G                                 第七轮 G(下标6) 获胜
      
  通过对比F(8,3) 和  F(7,3)的求解过程:我们会发现,F(7,3)其实就是求解F(8,3)时从第二轮开始的解。并且标记一下最终结果G的下标变化如下:
      下标              0   1   2   3   4   5   6   7 
      F(8,3)=6         A   B   C   D   E   F   G   H        
      F(7,3)=3         D   E   F   G   H   A   B         
      F(6,3)=0         G   H   A   B   D   E             
      F(5,3)=3         B   D   E   G   H                 
      F(4,3)=0         G   H   B   D                     
      F(3,3)=1         D   G   H                         
      F(2,3)=1         D   G                             
      F(1,3)=0         G                                 
   此时的问题转化为 如果我们知道了F(i,3)的解 如何来求F(i+1,3)的解呢  让我们利用F(8,3) 和 F(7,3)看一下是否有什么规律
      下标              0   1   2   3   4   5   6   7 
      F(8,3)=6         A   B   C   D   E   F   G   H        n=8 m=3
      F(7,3)=3         D   E   F   G   H   A   B            n=7 m=3
      从F(8,3)到F(7,3)(G下标变换)的操作步骤(记住,我们只关心G的下标):
            ① 将整体 左移 3(m)位,并将左边溢出的 第[0,2]([0,m-1])位的元素放到其后 ②再删除最后一个元素C。  F(7,3)=(F(8,3)-3)%8   (-3相当于是左移   %8 相当于是处理溢出) 
      那么反推,从F(7,3)到F(8,3)的操作步骤:
            ① 先补上最后一个元素C, ② 再 将整体右移 3(m)位,并将右边溢出的元素放在其前。                  F(8,3)=(F(7,3)+3)%8   (+3相当于是右移   %8 相当于是处理溢出)
      综上,我们得到递推规律 F(n,m)=(F(n-1,m)+m)%n.

复杂度:时间复杂度O(n) 空间复杂度O(n)

 

def lastRemaininng2(n, m):
    res = 0  # f(0)=0    如果n=5  则  0 1 2 3 4  求到f(4)即可
    for i in range(2, n + 1):
        res = (res + m) % i  # 注意 此处 应针对i取余   因为此时的i是当下f(n)的n
    return res

路虽远,行则将至。事虽难,做则必成 。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值