看这篇博客后https://blog.youkuaiyun.com/yanweibujian/article/details/50876631?utm_source=app照自己理解写的。
/* 约瑟夫环问题 */
/*
问题描述:
有10个人,每次报到3的人被杀掉,被杀掉的人的下一个人重新开始从1数,求最后幸存的那个人。
如:
报数为3的人
||
\/
1: 0 1 【2】 3 4 5 6 7 8 9
2: 3 4 【5】 6 7 8 9 0 1
3: 6 7 【8】 9 0 1 3 4
4: 9 0 【1】 3 4 6 7
5: 3 4 【6】 7 9 0
6: 7 9 【0】 3 4
7: 3 4 【7】 9
8: 9 3 【4】
9: 9 3 【9】
最后剩下的人是编号为4的人
方法一:使用循环链表去模拟,但是当要有m个人,报到n个数时,就要循环(n * (m - 1))次,复杂度高,想想能不能直接定位要杀掉的人的编号,
那样就不用去模拟数到3的位置是哪个。显然还是使用环形队列的去模拟这个过程,可以使用数组去存储,那么就会产生这样的情况:
每次杀掉的那个人就是在数组下标为2的人。数组头就会存放成为下标为3的位置的数,这里面存在一个映射关系:
旧数组下标 0 1 2 3 4 5 6 7 8 9 杀掉一个以后------>
新数组下标 7 8 0 1 2 3 4 5 6 杀掉一个以后------>
更新的下标 4 5 6 7 0 1 2 3 杀掉一个以后------>
1 2 3 4 5 6 0 杀掉一个以后------>
5 0 1 2 3 4 杀掉一个以后------>
2 3 4 0 1 杀掉一个以后------>
0 1 2 3 杀掉一个以后------>
1 2 0 杀掉一个以后------>
1 0 杀掉一个以后------>
1
因为:(旧数组下标 - 3) % (10 - 1) = 新数组下标 PS:因为是环形队列,所以下标为0 1 的那两个相当于是10 11
所以:旧数组下标 = (新数组下标 + 3) % 10;
则:当表示m个人,报到n就被杀时:
old = (new + n) % m;
再看一下old与new的关系:
old可以表示的是m个人,报到数为n,
new表示m - 1个人,报到数为n。 PS:因为新数组也是从0 - 8;
那么:
f(m, n)表示m个人,报到n时数组的下标。
f(m, n) = (f(m - 1, n) + n) % m;
那么可以映射他们之间的任意的下标关系。
如果使用f(m, n, p)来表示第p个被杀的人。
f(m, n, 1) = (n - 1) % m;
f(m, n, 2) = (f(m - 1, n, 2 - 1) + n)