目錄
問題重述:
思路解析_1:
**實現_1:
思路解析_2:
**實現_2:
題目:0,1,……,n-1這n個數字排成乙個圓圈。從數字0開始每次從這個圓圈裡刪除第m個數字。求出這個圓圈裡剩下的最後乙個數字。
用乙個鍊錶來儲存元素,當遍歷到鍊錶尾部的時候,讓迭代器再次指向頭部,由此形成乙個環。我們就在鍊錶中去遍歷,每次遇到第m個數字,刪除即可,直至鍊錶中剩下最後乙個元素。
class solution
return *current;}};
可以發現,解析1中的思路需要對儲存資料的鍊錶進行多次遍歷,時間效率是非常低的。
接下來講解另一種思路,說實話,挺複雜的,但是**簡單,執行效率高。我盡量以直白的語言描述。
首先,在這n個數字中,第乙個被刪除的數字應該是(m-1)%n,記為k。那麼剩下的數字為0~k-1和k+1~n-1。那麼下一次的遍歷順序應該是:k+1,k+2,……,,n-1,0,1,……k-2,k-1。
我們不妨定義乙個函式f(n,m)來表示n個數字中最後乙個刪除的數,那麼在f(n,m)中,刪除第乙個數之後,剩下的數的排序要從當前刪除數字的後面開始進行計數。因此我們可以再定義乙個函式,記為g(n-1,m),由於函式g和函式f都是求最後乙個刪除的數字,因此必定有f(n,m) = g(n-1,m)。
接下來將f(n,m)刪除第乙個數之後剩下的資料重新進行定位:
k+1:0
k+2:1
n-1:n-k-2
0:n-k-1
1:n-k
k-1:n-2
我們定義這種對映為p,則有p(x)=(x-k-1)%n,x為當前數字,p(x)為x在刪除k後的重新排序的位置。那麼p的逆對映為c(x) = (x+k+1)%k。那麼x表示排序後的位置,c(x)表示x位置處的數字。
現在我們將這種對映帶入前面的表示式,前面我們提到了f和g兩個函式,這兩個函式本質上的區別就是數字的下標值變了,那麼具體是怎麼變的呢,就是上面提到的對映。
那麼在g(n-1,m)=c[f(n-1,m)]=(f(n-1,m)+k+1)%n。那麼有下面遞迴公式:
其中n=1,表示只有乙個數,那麼最後乙個刪除的數肯定是0。接下來向上回溯,即可得到f(n,m)。
因此可以寫出如下簡單**:
int lastremaining(int n,int m)
刷題 劍指offer之圓圈中最後剩下的數字
題目 有n個人,圍成乙個環,編號為 0 1 2 3 n 1,從第乙個人開始迴圈報數 從1開始 假設數到m的那個人出列,然後從下乙個人繼續數數,數到m出列,以此迴圈,最後那個人為勝利者,求勝利者的編號。這其實就是有名的約瑟夫問題。可以使用陣列或者鍊錶來模擬這n個人,每次刪除第m個人,直到只剩下乙個人為...
劍指Offer 圓圈中最後剩下的數
每年六一兒童節,牛客都會準備一些小禮物去看望孤兒院的小朋友,今年亦是如此。hf作為牛客的資深元老,自然也準備了一些小遊戲。其中,有個遊戲是這樣的 首先,讓小朋友們圍成乙個大圈。然後,他隨機指定乙個數m,讓編號為0的小朋友開始報數。每次喊到m 1的那個小朋友要出列唱首歌,然後可以在禮品箱中任意的挑選禮...
劍指offer 圓圈中最後剩下的數字
例如,0,1,2,3,4這五個數字組成的圓圈,每次從數字0開始刪除第3個元素,依次刪除的數為2,0,4,1,那麼剩下的為3。思路1 可以用stl模板庫裡面的list來模擬這個環形的鍊錶,因為list是線性的,所以為了實現環形的鏈,可以在遍歷到鏈的末尾的時候跳轉到鏈的開頭,這樣就相當於乙個環形鍊錶了,...