题目难度:中等
题目考察:约瑟夫环,链表
题目内容:每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)
如果没有小朋友,请返回-1

题目分析:
首先这题要每次删除一个数,可以使用数组或者链表解决这一题,数组可以O(1)查找 O(n)删除,链表可以O(1)删除,O(n)查找,果然,鱼和熊掌不可兼得(块状链表貌似可以兼得hh)但是这题实际上是约瑟夫环问题,我看题解上没有写的很清楚的。。。
首先先给出链表的做法
算法1:链表

class Solution {
public:
    int LastRemaining_Solution(int n, int m)
    {
        if (n <= 0) return -1; 
            //人数为0
        list<int> lt;
            //直接用stl里面封装好的链表即可
        for (int i=0; i<n; ++i) lt.push_back(i); 放入n个人 int index="0;" 要删除的人 while (n> 1) {
            index = (index + m - 1) % n;
                //n个人,从index开始报数,报到m-1的人
            auto it = lt.begin();
            std::advance(it, index); 
            //该函数可以将it向后移动index个位置
            lt.erase(it);
            //删除链表元素
            --n;
        }
        return lt.back();
    }
};

很经典的链表的使用不在细说,下面来说一说约瑟夫环问题
实际上这题就是约瑟夫环问题
图片说明
理解了上面,这就很简单了
算法2:递推

class Solution {
public:
    int LastRemaining_Solution(int n, int m)
    {
        if( n <= 0 || m <= 0 )     return -1;  
        int ans = 0 ;
        //最后一个删除的肯定是0
        for(int i =  2; i <= n ; i++){
            ans = ( ans + m ) % i;
               //这一次删除的数=(上一次删除的数+m)%(上一次剩的人数)
        }
        return ans;
    }
};

时间复杂度O(n)
空间复杂度O(1)
代码非常优美简洁,效率十分高