题目描述
0
,
1
,
…
,
n
−
1
0,1,\dots ,n-1
0,1,…,n−1这
n
n
n 个数字排成一个圆圈,从数字
0
0
0 开始,每次从这个圆圈里删除第
m
m
m 个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。
例如,
0
、
1
、
2
、
3
、
4
0、1、2、3、4
0、1、2、3、4 这
5
5
5 个数字组成一个圆圈,从数字
0
0
0 开始每次删除第
3
3
3 个数字,则删除的前
4
4
4 个数字依次是
2
、
0
、
4
、
1
2、0、4、1
2、0、4、1,因此最后剩下的数字是
3
3
3 。
输入: n = 5, m = 3
输出: 3
输入: n = 10, m = 17
输出: 2
限制: 1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1≤n≤105, 1 ≤ m ≤ 1 0 6 1 \le m \le 10^6 1≤m≤106
思路
参考了:leecode官方题解
- 递归思路,假设 f ( n , m ) f(n,m) f(n,m) 返回的是, n n n 个人,每 m m m 个淘汰一人,最后剩下的人的编号
- 第一次消除的是编号为 y = ( m − 1 ) % n y=(m-1)\%n y=(m−1)%n 的人
- 令 x = f ( n − 1 , m ) x=f(n-1,m) x=f(n−1,m),那么 f ( n , m ) = ( y + x + 1 ) % n = ( m + x ) % n f(n,m)=(y+x+1)\%n=(m+x)\%n f(n,m)=(y+x+1)%n=(m+x)%n
- f ( 1 , m ) = 0 f(1,m)=0 f(1,m)=0
这里的 f ( n , m ) = ( m + x ) % n f(n,m)=(m+x)\%n f(n,m)=(m+x)%n 相当于一个加了一个偏移量。比如 f ( 10 , 17 ) f(10,17) f(10,17),第一个淘汰的人的编号为 6 6 6,那么 f ( 9 , 17 ) f(9,17) f(9,17) 就不是从编号为 0 0 0 的人开始数,而是从编号为 7 7 7 的人开始数。同样,最后剩下的人的编号也不是 x = f ( 9 , 17 ) x=f(9,17) x=f(9,17),它同样要加上一个偏移量: f ( 10 , 17 ) = ( 6 + 1 + f ( 9 , 17 ) ) % 10 f(10,17)=(6+1+f(9,17))\%10 f(10,17)=(6+1+f(9,17))%10。
代码
int lastRemaining(int n, int m) {
if(n==1) return 0;
int x=lastRemaining(n-1,m);
return (m+x)%n;
}
时间 O ( n ) O(n) O(n),空间 O ( n ) O(n) O(n)。要求空间 O ( 1 ) O(1) O(1),递归改迭代:
int lastRemaining(int n,int m){
int res=0;
for(int i=2;i<=n;i++) res=(res+m)%i;
return res;
}