链队列约瑟夫环c++代码_约瑟夫环新思路——只关心最终活着那个人的序号变化...

解题思路

阅前提示(全文最重要的点):

只关心最终活着那个人的序号变化

1 约瑟夫问题

这个问题实际上是约瑟夫问题,这个问题描述是

N个人围成一圈,第一个人从1开始报数,报M的将被杀掉,下一个人接着从1开始报。如此反复,最后剩下一个,求最后的胜利者。

这个问题自己之前刷剑指的时候写过,但是今天根本想不起之前的思路了,说明没有深刻理解,为了不再犯错,这次深入理解了一遍,于是有了这篇文章

看了很多大佬的题解,都是用数字在进行举例,看完还是有一些疑惑,直到看了底部参考资料那篇文章才豁然开朗

这里换了个角度举例,或许会更清晰一些,欢迎大家讨论,并不吝赐教!

2 问题转换

既然约塞夫问题就是用人来举例的,那我们也给每个人一个编号(索引值),每个人用字母代替

下面这个例子是N=8 m=3的例子

我们定义F(n,m)表示最后剩下那个人的索引号,因此我们只关系最后剩下来这个人的索引号的变化情况即可

28d7e94fdb8b0d7ce79f47bfc7f759b3.png

从8个人开始,每次杀掉一个人,去掉被杀的人,然后把杀掉那个人之后的第一个人作为开头重新编号

第一次C被杀掉,人数变成7,D作为开头,(最终活下来的G的编号从6变成3)

第二次F被杀掉,人数变成6,G作为开头,(最终活下来的G的编号从3变成0)

第三次A被杀掉,人数变成5,B作为开头,(最终活下来的G的编号从0变成3)

以此类推,当只剩一个人时,他的编号必定为0!(重点!)

3 最终活着的人编号的反推

现在我们知道了G的索引号的变化过程,那么我们反推一下

从N = 7 到N = 8 的过程

如何才能将N = 7 的排列变回到N = 8 呢?

我们先把被杀掉的C补充回来,然后右移m个人,发现溢出了,再把溢出的补充在最前面

神奇了 经过这个操作就恢复了N = 8 的排列了!

d7441927ad1c1d8ffd28a57b7dbd846f.png

因此我们可以推出递推公式f(8,3) = [f(7, 3) + 3]%8

进行推广泛化,即f(n,m)=[f(n−1,m)+m]%n

4 递推公式的导出

再把n=1这个最初的情况加上,就得到递推公式

ea510dbe9ca4ffd26da761ff61c59930.png

为了更好理解,这里是拿着约瑟夫环的结论进行举例解释,具体的数学证明请参考维基百科。

5 代码

照着递推公式写即可,也可写成递归的形式

0402013db64db9e2cfae20803c28cc94.png

链接:https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/solution/huan-ge-jiao-du-ju-li-jie-jue-yue-se-fu-huan-by-as/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值