刷題 劍指offer之圓圈中最後剩下的數字

2021-09-13 12:47:31 字數 2435 閱讀 3018

題目:有n個人,圍成乙個環,編號為 0、1、2、3、、、n-1,從第乙個人開始迴圈報數(從1開始),假設數到m的那個人出列,然後從下乙個人繼續數數,數到m出列,以此迴圈,最後那個人為勝利者,求勝利者的編號。

這其實就是有名的約瑟夫問題。

可以使用陣列或者鍊錶來模擬這n個人,每次刪除第m個人,直到只剩下乙個人為止。

使用陣列刪除元素的複雜度較高,鍊錶是最優選擇,c++ stl中的鍊錶用的不太熟練,所以自己寫乙個。為了刪除方便,選擇雙向鍊錶,單向鍊錶刪除的時候還需要兩個指標,很麻煩。

class solution ; // 鍊錶節點

int lastremaining_solution(int n, int m)

//找到了第m個 開始刪除

head->parent->next = head->next;

head->next->parent = head->parent;

head = head->next;

num --; // 剩餘人數減1

}return head->val;}};

這種演算法時間複雜度為o(mn),空間複雜度為o(n)。

感覺應該存在某種規律,但我等數學渣渣並不能夠推導出來。

看完書上的解答,表示有點繞,現在用自己的話解釋一遍:

f(n,m):表示 每次在n個數字0,1,...,n-1中刪除第m個數字最後剩下的數字(也就是要求的結果)。(注意,要求數字標號需要是連續的,所以後面刪除乙個元素後標號不連續了,需要重新標號)。

在這n個數字中,第乙個被刪除的數字是(m-1)%n(取餘的原因是m可能比n大),記作k,則k=(m-1)%n。刪除後的序列為 0,1,...,k-1,k+1,...,n-1。由於下一次刪除是從k+1開始計數的,所以相當於從標號為k+1,k+2,...,n-1,0,1,2,...,k-1的序列中繼續刪除第m個數字,最終剩下的數字就是結果。

剩下的n-1個數字如果重新按順序標號得到序列0,1,...,n-2,則每次刪除第m個數,最後剩下的數字就是f(n-1,m)。由於重新標號了,所以並不是f(n,m)=f(n-1,m)! 那麼f(n-1,m)對應的數字在修改標號之前是什麼數呢?

事實上,原先的不連續的序列a(k+1,k+2,...,n-1,0,1,2,...,k-1)變成了序列b(0,1,...,n-2),而我們主要是想知道如何從序列b中的某個數找到序列a中對應的關係,先建立個對映**:

b序列序列a

0k+1

1k+2

n-k-2

n-1n-k-1

0n-k

1n-2

k-1f(n-1,m)

(f(n-1,m)+k+1)%n

根據**,可以很直觀的看出,在b序列中數字x,對應於a序列中的(x+k+1)%n(注意:必須取餘數,因為b序列中為n-k,而n-k+k+1n+1,必須取餘數才能得到1)。所以在b序列中標號為f(n-1,m),對於在a序列中就為(f(n-1,m)+k+1)%n

還記得k嗎,k就是在第一次刪除的時候刪掉的數(與n有關的變數),k=(m-1)%n

將其帶入上面的式子,就得到:

(f(n-1,m)+k+1)%n = (f(n-1,m)+(m-1)+1)%n = (f(n-1,m)+m)%n

因此,我們就得到了這個遞迴公式,而當n=1的時候,也就是序列中只有標號為0的數字,顯然最後剩下的數字就是0,所以整個公式就是:

根據這個公式,寫**就很簡單了。

class solution 

};

這種演算法的時間複雜度是o(n),空間複雜度是o(1),遠遠優於第一種演算法,但是推導複雜,數學渣渣表示如果沒見過這個題,絕對推導不出來。。。

使用鍊錶模擬的常規解法必須掌握,數學推導,那就看狀態吧。。

劍指offer第二版--面試題62

劍指offer刷題 圓圈中最後剩下的數字

目錄 問題重述 思路解析 1 實現 1 思路解析 2 實現 2 題目 0,1,n 1這n個數字排成乙個圓圈。從數字0開始每次從這個圓圈裡刪除第m個數字。求出這個圓圈裡剩下的最後乙個數字。用乙個鍊錶來儲存元素,當遍歷到鍊錶尾部的時候,讓迭代器再次指向頭部,由此形成乙個環。我們就在鍊錶中去遍歷,每次遇到...

劍指Offer 圓圈中最後剩下的數

每年六一兒童節,牛客都會準備一些小禮物去看望孤兒院的小朋友,今年亦是如此。hf作為牛客的資深元老,自然也準備了一些小遊戲。其中,有個遊戲是這樣的 首先,讓小朋友們圍成乙個大圈。然後,他隨機指定乙個數m,讓編號為0的小朋友開始報數。每次喊到m 1的那個小朋友要出列唱首歌,然後可以在禮品箱中任意的挑選禮...

劍指offer 圓圈中最後剩下的數字

例如,0,1,2,3,4這五個數字組成的圓圈,每次從數字0開始刪除第3個元素,依次刪除的數為2,0,4,1,那麼剩下的為3。思路1 可以用stl模板庫裡面的list來模擬這個環形的鍊錶,因為list是線性的,所以為了實現環形的鏈,可以在遍歷到鏈的末尾的時候跳轉到鏈的開頭,這樣就相當於乙個環形鍊錶了,...