写在前面
很久没学习了。
被前队友拉去看了一个简单的入门级算法题吧。
应该是很久之前就看过的东西
凭我这个记性,很明显是忘了
重新看一下 记录一下
问题描述
N个人围绕一圈报数, 喊道m的人被处死, 下一个人从头开始继续报数 为最后唯一生存者是第几个人。
解法
解法一 自然是用链表模拟 复杂度O(n*m) 爆炸复杂度
解法二 公式法
主要思考如何解释推到该公式
看到一篇博客特别好,解释的十分清楚
先抛出一个样例
如果9个人喊道3的人被处死 那么生存着是第几个
给每个人编号从1开始
有1 2 3 4 5 6 7 8 9
第一轮从1开始报数 3被处死
第二轮从4开始报数 6被处死
第三轮从7开始报数 9被处死
……
0 | 1 | 2* | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
1 | 2 | 3* | 4 | 5 | 6 | 7 | 8 | 9 |
4 | 5 | 6* | 7 | 8 | 9 | 1 | 2 | .. |
7 | 8 | 9* | 1 | 2 | 4 | 5 | .. | .. |
1 | 2 | 4* | 5 | 7 | 8 | .. | .. | .. |
5 | 7 | 8* | 1 | 2 | .. | .. | .. | . |
1 | 2 | 5* | 7 | |||||
7 | 1 | 2* | ||||||
7* | 1 | |||||||
1 W |
由👆表可知最后幸存者为1号
1 | 不妨 设F(n,m) = x //n个人 ,喊道m被处死 幸存者的下标为x |
感觉一脸懵逼? 怎么推导的?
现在开始推导公式
简单点讲:
每一次死的都是 下标为2(喊到3)的人死
死去的人的下一个人下标向前挪三位 然后开始从1报数
因为人越死越少 所以会产生循环 所以模一个当前剩余人数(死人不会报数)
以此类推 N个人 喊道m被处死 数组如何移动?
每杀掉一个人,下一个人成为头,即数组整体向前挪m位
如果已知F(n-1,m) = x
则 F(n,m) =(x + m) % n
从F(1 , m) = 0 逆向递推至n 得到 F(n,m)结果
代码实现
1 | int cir(int n,int m) |