1.数学递推,递归,时间复杂度O(n)
结论:
分析:
下面用数学公式推导的方法,解决约瑟夫环经典问题。
第一步,这n个人我们给每一个人一个编号 0 ,1 ,2 ······ n-2,n-1
第二步,当第一轮游戏结束后,这n个人少就变成了n-1个人
第三步,将第一轮结束后剩下的人里面第一个报数的记为m,则这n-1个人 的编号为
m,m+1,m+2······n-2,n-1,0,1,2,······m-2(m-1也就是第一轮结束后出局的那个人)
第四步,也是最关键的一步,这n-1个人我们是不是也可以当成第一步那样重新来个编号,如下:
m,m+1,m+2······n-2,n-1,0, 1, 2,······m-2 0 ,1 ,2 ······ n-m n-3,n-2(少了一个人所以到n-2)
第五步 我们来推导数学公式。假设有n个人时,最后剩下的人的编号为f(n).
- 在四步的转换中k - -> 0,那么当我们从反过来从发f(n-1)的情况推f(n)的情况的时候,如果在n-1情况下f(n-1)是最后胜出的人,那么在n的情况下 f(n-1)+m就是最后胜出的人。
由此,得出公式f(n)=(f(n-1)+m)%n
,f(1)=0.
两种形式实现递推
1.循环
class Solution {
public:
//约瑟夫环
int LastRemaining_Solution(int n, int m)
{
if(!n&&!m)return -1;
int lastpeople=0;
for (int i = 2; i <= n; i++)
{
lastpeople = (lastpeople + m) % i;
}
return lastpeople;
}
};
2.递归
class Solution {
public:
//约瑟夫环
int LastRemaining_Solution(int n, int m)
{
if (!n&&!m)return -1;
else if (n == 1)return 0;
else return (LastRemaining_Solution(n - 1, m) + m) % n;
}
};
参考这篇博客代码有误,应该i=2
开始。