在做编程题时遇上约瑟夫环问题:
0,1,,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。
题目来源:力扣(LeetCode)如果看不懂可以百度其它约瑟夫环问题
链接:https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof
现在我们列个表来举例:假设人总数n=5,每次杀第m=3个人,我们可以列出如下表
0 | 1 | 2 | 3 | 4 |
1 | 2 | 3 | 4 | 5 |
4 | 5 | 1 | 2 | |
2 | 4 | 5 | ||
2 | 4 | |||
4 |
第一行为每个数字的下标位置,从0开始:
现在假设我们已经知道了最后一个留下来的是4号,那么当在倒数第二次杀人的时候我们怎么直接找出4号呢?
即转化位求在倒数第二行查找4号的位置:
我们可以由规则知道,其实每杀一个人,则表中的整行向左移动m=3位,那么由倒数第一行回到倒数第二行4号的位置就应该右移m=3位,则我们可以判断出,此时4号的位置是3+0,如果不进行轮转的话,那么四号的位置就是3,但是此时数组大小只有2,即它所在的位置需要对数组大小进行取余(这个类似hash表的插入方式),那么在倒数二行找到4号位置就是3%2=1了。
同理,在倒数第三行要找到4号:
还得将倒数第二行的位置向右移m=3位才是它在第三行的实际位置,即1+m=4,但是仍然的,此时数组大小为3,我们必须对它进行取余即在倒数三行的位置为4%3=1;
依此类推,我们知道任何n的时候,其对应结果的位置都是上一结果n-1的位置右移m位后对n取余
即可以得到公式,f(n,m)=(f(n-1,m)+m)%n;
式子中 f(n,m)表示的是在人数等于n的时候,存活者所在的位置,且易知f(1,m)=0;
一下是c++程序,返回的结果是第几个人,从1开始;与leetcode问题返回结果有所不同,请注意
//返回的是第几个人,从1开始
int Survival(int n, int m)
{
int sur = 0;
//从倒数第二行开始算
for(int i=2; i<=n; i++)
{
sur = (sur + m) % i ;//即获得当前人数时,此幸存者的位置
}
return sur + 1;//因为是位置,所以下标从0开始,比实际人的标号小1,所以要加回去
}