题意:

  • n个人成环,编号从1到n,从1开始报数,报数到m的人离开,由下一个人继续从1开始报数,循环n-1轮之后只剩下一个人,求这个人的初始编号是多少。

方法一:

思路分析:

  • 因为最后只剩下一个人,所以我们可以从最后剩下的编号入手,看能不能倒推得到最开始的编号。首先画出图尝试找一下规律。
    图片说明
  • 如上图所示,我们倒推:
    第四轮结束,最后留下来的人的编号为 1;
    第三轮结束,最后留下来的人的编号为 1+2=3; 3%2=1,编号为1;
    第二轮结束,最后留下来的人的编号为 1+2=3;
    第一轮结束,最后留下来的人的编号为 3+2=5(因为5>4) 所以5%4=1;
    第一轮开始,最后留下来的人的编号为 1+2=3;
  • 我们可以得到规律是,(x+m-1)%n+1 是倒推的规律。此处先-1,+1的原因是初始从1开始编号,编号范围[1,n]与取模运算的值域范围[0,n-1]有差异,所以需要先减一后加一。如果编号范围是[0,n-1]的话,那么该规律应该为(x+m)%n
  • 下面我们对于该规律(x+m)%n的一般化验证。
    图片说明
  • 因此利用(x+m-1)%n+1的规律递推即可得到答案。

代码如下:

class Solution {
public:
    /**
     * 
     * @param n int整型 
     * @param m int整型 
     * @return int整型
     */
    int ysf(int n, int m) {
        // write code here
        int x=1;//x为留下来的人在最后一轮结束后的编号
        for(int i=2;i<=n;i++){
            x=(x+m-1)%i+1;//i为每轮人数数量。从2->n
        }
        return x;
    }
};

复杂度分析:

时间复杂度:,循环n-1轮。
空间复杂度:

方法二:

根据上述的递推式,也可使用递归的方式来解决。使用函数f(n,m)来表示人数为n时,最后留下来的人的编号。
有(f(n-1,m)+m-1)%n+1=f(n,m)。

代码如下:

class Solution {
public:
    /**
     * 
     * @param n int整型 
     * @param m int整型 
     * @return int整型
     */
    int helper(int n,int m){
        if(n==1)
            return 1;
        int x=helper(n-1,m);//下一轮的编号
        return (x+m-1)%n+1;//递推公式
    }
    int ysf(int n, int m) {
        // write code here
        return helper(n,m);
    }
};

复杂度分析:

时间复杂度:,递归次数
空间复杂度:,递归深度