圓圈中最後剩下的數字(36)

題目

【首先,讓小朋友們圍成一個大圈,小朋友的編號是從0到n-1。然後隨機指定一個數m,讓編號爲0的小朋友開始報數。每次喊到 m-1 的那個小朋友要出列唱首歌,然後可以在禮品箱中任意的挑選禮物,並且不再回到圈中,從他的下一個小朋友開始,繼續0…m-1報數…這樣下去…直到剩下最後一個小朋友,求最後一個小朋友的編號。如果沒有小朋友,請返回-1】


方法一

1、分析

  • 該題是約瑟夫環問題,可以採用環形鏈表的方式來模擬圓圈。該環形鏈表共有n個節點,每次刪除第m-1個節點(從0開始計數)。
  • 使用標準模板庫中的list來進行操作,每次刪除一個元素需要運行 m 步,若共有n個數字,則其時間複雜度爲 O(mn)O(mn) ,同時還需要一個輔助的鏈表來模擬圓圈,其空間複雜度 O(n)O(n)

2、代碼

class Solution {
public:
    int LastRemaining_Solution(int n, int m)
    {
        if(n<1 || m<1)
            return -1;
        list<int> num;
        for(int i=0;i<n;++i)
            num.push_back(i);
        list<int>::iterator curNum=num.begin();
        while(num.size()>0)
        {
            if(num.size()==1)
                return  *curNum;
            //注意初始時迭代器是指向第一個元素,所以是從j=1開始,而不是0
            for(int j=1;j<m;++j)
            {
                curNum++;
                if(curNum==num.end())
                {
                    curNum=num.begin();
                }
            }
            list<int>::iterator nextNum=++curNum;
            if(nextNum==num.end())
                nextNum=num.begin();
            num.erase(--curNum);
            curNum=nextNum;
        }
    }
};

方法二:

1、分析

  • 由於使用環形鏈表的方式來刪除對應的元素,每次刪除元素會有大量的重複遍歷過程,且需要藉助額外的空間,所以可以使用更好的方法。
  • 當有n個元素時,刪除第m個元素,則第一個被刪除的元素爲 k=(m1)%nk=(m-1)\%n (因爲m可能會大於n,所以要對n取模)。剩下的爲 0,1,2······,k-1, k+1,···,n-1 。並且下一次刪除數字時從 k+1 開始計數,相當在剩下的序列中 k+1 排在最前面: k+1,···,n-1 , 0,1,2······,k-1。
  • 可以將該過程看成關於 m 和 n 的函數,設: f(n,m)f(n,m) 爲在n個數字中不斷的刪除第m個數字,最後所剩下的數字。設 g(n1,m)g(n-1,m) 爲刪除第一個數字之後,所剩下的數字中再不斷的刪除第m個數字,最後所剩下的數字。顯然 f(n,m)=g(n1,m)f(n,m)=g(n-1,m)
  • 接下來將 k+1,···,n-1 , 0,1,2······,k-1 這些數字映射成 0~n-2 的序列

k+1 --> 0
k+2 --> 1
·······
n-1 --> n-k-2
0 --> n-k-1
1 --> n-k
····
k-1 --> n-2

最終的迭代公式爲:f(n,m)={0n=1[f(n1,m)+m]%nn>1f(n,m)=\begin{cases} 0 & n=1\\ [ f(n-1,m)+m]\%n & n>1 \end{cases}
2、代碼

class Solution {
public:
    int LastRemaining_Solution(int n, int m)
    {
        if(n<1 || m<1)
            return -1;
        int last=0;
        for(int i=2;i<=n;++i)
        {
            last=(last+m)%i;
        }
        return last;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章