【数学,递归&递推,约瑟夫环】
-
方法1:链表模拟
- (n-1)轮,删除 O ( 1 ) O(1) O(1)
- 复杂度 O ( m n ) O(mn) O(mn),不能接受
-
方法2:数学,递归&递推
-
约瑟夫环问题:n个人排成一个圆圈做游戏,每轮游戏去掉第m个人,然后从第(m+1)个开始计数开始新一轮,直到剩余一个人。
-
分析:
-
共n个数,每轮去掉一个数,显然需要有(n-1)轮,直到最后剩余1个数为止
-
每轮去掉的都是第m个数,会把第(m+1)个数移到第一位
-
所以对于有i个数的数组,它去掉第m个数,把第(m+1)个数移到第一位后,变成了有(i-1)个数的数组
- 这两个数组(即两个状态)间有什么联系?
- 因为有i个数的数组,把第(m+1)个数移到了第一位,对于第m个数,如果没被去掉,应该在有(i-1)个数的数组的最后一位
- 设有i个数的数组的状态为(i),有(i-1)个数的数组的状态为(i-1)
- 所以状态(i-1)是把状态(i)的元素循环左移了m位!
- 所以对状态(i)来说,它里面元素对应的编号,应该是状态(i-1)元素的对应编号循环右移m位得到的
- 即f(i) = (f(i-1) + m) % n
- 但其它元素在游戏过程都被去掉了,只有最终剩余的那个数一直存在最后一轮(即状态:数组中只有1个数),所以这个递归式只适用于最终剩余的那个元素
- 正好是题目要求求的
- f[i]是最终剩余的那个元素的编号
- 递归边界:当数组中只有1个数时,游戏结束,f[1]显然为0
- 写成递归那就从f[1]=0开始正向推,直到f[n]
- 该题元素与编号是一一对应关系,所以求编号就是求元素
- 因为有i个数的数组,把第(m+1)个数移到了第一位,对于第m个数,如果没被去掉,应该在有(i-1)个数的数组的最后一位
- 这两个数组(即两个状态)间有什么联系?
-
举例(为清晰,把数组中的元素写成字母)
-
设n=8,m=3
-
0 1 2 3 4 5 6 7 A B (C) D E F [G] H // n=8, id = (3+3)%8=6 D E (F) [G] H A B //n=7, id = (0+3)%7 = 3 [G] H (A) B D E //n=6, id = (3+3)%6 = 0 B D (E) [G] H //n=5, id = (0+3)%5 = 3 [G] H (B) D //n=4, id = (1+3)%4 = 0 D [G] (H) //n=3, id = (1+3) % 3 = 1 (D) [G] //n=2,id = (0+3) % 2 = 1 [G] //n=1,id = 0
-
-
-
-
-
递归:
int lastRemaining(int n, int m) {
if(n == 1) return 0;
return (lastRemaining(n-1, m)+m)%n;
}
递推:
int lastRemaining(int n, int m){
int pos = 0;
for(int i = 2; i <= n; i++){
pos = (pos+m) % i;
}
return pos;
}