约瑟夫环
题目 约瑟夫环问题
0,1,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。
思路
将问题建模为函数
f
(
n
,
m
)
f(n,m)
f(n,m),该函数返回值为最终留下的元素的序号。
首先, 长度为
n
n
n的序列会先删除第
m
%
n
m\%n
m%n个元素,然后剩下一个长度为
n
−
1
n-1
n−1的序列,于是可以递归求解
f
(
n
−
1
,
m
)
f(n-1,m)
f(n−1,m),得到对于剩下的
n
−
1
n-1
n−1个元素,最终留下的元素的序号,
f
(
1
,
m
)
f(1, m)
f(1,m)即为所求。
由于删除了第
m
%
n
m\%n
m%n个元素,将序列的长度变为
n
−
1
n-1
n−1。当知道
f
(
n
−
1
,
m
)
f(n-1,m)
f(n−1,m)对应的答案
x
x
x后,就可以知道,长度为
n
n
n的序列最后一个删除的元素,应该是从
m
%
n
m\%n
m%n开始的第
x
x
x个元素。因此
f
(
n
,
m
)
=
(
m
%
n
+
x
)
%
n
=
(
m
+
x
)
%
n
f(n,m)=(m\%n+x)\%n=(m+x)\%n
f(n,m)=(m%n+x)%n=(m+x)%n
递归:
- 时间复杂度: O ( n ) O(n) O(n),需要求解的函数值有 n 个。
- 空间复杂度: O ( n ) O(n) O(n),递归深度为n。
迭代:
- 时间复杂度: O ( n ) O(n) O(n),需要求解的函数值有 n 个。
- 空间复杂度: O ( 1 ) O(1) O(1),只使用常数个变量。
C++ 递归
class Solution {
public:
int lastRemaining(int n, int m) {
return func(n, m);
}
private:
int func(int n, int m)
{
if(n==1)
return 0;
int x = func(n-1, m);
return (m+x)%n;
}
};
python 迭代
class Solution:
def lastRemaining(self, n: int, m: int) -> int:
f = 0
for i in range(2, n+1):
f = (m+f)%i
return f