左神课堂---环形单链表的约瑟夫---进阶8视频

题目:

 

环形单链表的约瑟夫问题


据说著名犹太历史学家Josephus有过以下故事:在罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,报数到3的人就自杀,然后再由下一个人重新报1,报数到3的人再自杀,这样依次下去,直到剩下最后一个人时,那个人可以自由选择自己的命运。这就是著名的约瑟夫问题。现在请用单向环形链表描述该结构并呈现整个自杀过程。
输入:一个环形单向链表的头节点head和报数的值m。
返回:最后生存下来的节点,且这个节点自己组成环形单向链表,其他节点都删掉。
进阶:
如果链表节点数为N,想在时间复杂度为O(N)时完成原问题的要求,该怎么实现?

思路:

题目要求时间复杂度为O(n),所以不能够用模拟的方法求解。

如果我们能够有一个F函数来反映新编号和旧编号之间的对应关系,那就再好不过了.

 

 

再求F(x)函数之前,我们必须先知道一个数学函数:

 

 

我们所求的S函数和F函数都是通过这个函数变换而来的.。

下面我们求S函数:

S(x)代表长度为i时数到x的人的编号

 

 

这样,我们就能够写出S函数的表达式:S(x)=(x-1)%i+1

接下来我们在S函数的基础上求F函数:

 

 

至此,我们就可以得到F函数的表达式:F(x)=(x-1+s)%i+1,其中F(x)代表旧编号,x代表新编号

其中表达式中s就是S(m)所计算的结果。将S(m)带入到F函数中可得:F(x)=(x+m-1)%i+1

这个式子中,m为已知量,x为未知量

这个式子在这个题目中就代表:旧编号=((新编号)+m-1)%(当前剩余的人数)+1

其中新编号是可以通过递归函数算出来的,当前剩余人数是不断递减的。

至此,有了这个式子,我们就可以写出递归函数来了,这道题完美走向结局。

代码:

​
int Get_F(int i)//得到人数为i时,最后存活的那个人的编号(旧编号)
{
    if(i==1) //如果只有一个人,那么这个人的编号就为1
        return 1;
    return (Get_T(i-1)+m-1)%i+1; //Get_T(i-1)求的是人数为i-1时最后存活的那个人的编号(新编号,新编号和旧编号在人数上相差一)
}

​

只写了核心部分的代码,别的地方就不写了。

分析一下为啥时间复杂度为O(n),通过递归函数可得,初始调用时i等于n,一只调用到i等于1时停止,每次递归函数里面的时间复杂度为O(1),所以时间复杂度为O(n)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值