約瑟夫環之遞迴演算法

2021-08-04 02:55:04 字數 1443 閱讀 7670

問題描述:

約瑟夫環是乙個數學的應用問題:已知n個人(以編號1,2,3…n分別表示)圍坐在一張圓桌周圍。由第乙個人開始報數,數到m的那個人出列;他的下乙個人又從1開始報數,數到m的那個人又出列;依此規律重複下去,直到最後剩下乙個人。

一般的思路就是通過乙個count計數的方法,迴圈遍歷鍊錶,逐一刪除。但是這樣的方法時間複雜度要有o(n×m),(總共要刪除n-1個數,每刪除乙個需要遍歷m次)。那有沒有什麼辦法直接就找到我們需要刪除的那個節點呢,比如給你鍊錶1→2→3→4→5→1,這是環狀鍊錶。如果m=3的話,最後留下的是第4個節點。這裡我們就需要借用數學的方式來進行推到公式,利用遞迴的方式求解了。

遞迴求解思路:

(我通過遞迴的方式,返回需要刪除第幾個節點,所以,節點編號從1開始,返回的也是第幾個節點)

第一次刪除第m個節點很簡單,就是m%n的那個節點,但是第二次刪除節點就有點困難了,為什麼,因為,你需要從第m+1的節點重新從1開始數,數到第m個節點再次刪除。其實,不知道你們有沒有發現,其實第二次開始數的第1個節點,就是上一次的m+1號節點。所以前乙個鍊錶節點和後乙個鍊錶節點對應的編號關係就是:

oldnum=(newnum+m-1)%(當前節點數)+1 (1)

下面從分析下:

根據公式(1)的關係,你就可以由新鍊錶找到對應就鍊錶的編號位子了。當鍊表中由i個節點時,編號對應的公式是:num(i) = (num(i-1)+m-1)%i +1;

(如果鍊錶從0開始編號的話,那麼公式就是num(i) = (num(i-1)+m)%i ),返回的是下標值,且最後num(1) = 0;)

**實現:

public

class josephusproblem

}public

static node josephuskill2(node head, int m)

node cur = head.next;

int tmp = 1; // 表示鍊錶長度

/* *計算鍊錶長度

*/while (cur != head)

tmp = getlive(tmp, m); // 返回鍊錶中應該刪除的那個值位置

while (--tmp != 0)

head.next = head;

return head;

}public

static

intgetlive(int i, int m)

//如果從0開始編號的話,此處(getlive(i - 1, m) + m) % i,返回的就是下標值

return (getlive(i - 1, m) + m - 1) % i + 1;//這個就是上述公式實現}}

約瑟夫環 遞迴演算法

假設下標從0開始,0,1,2 m 1共m個人,從1開始報數,報到k則此人從環出退出,問最後剩下的乙個人的編號是多少?現在假設m 10 0 1 2 3 4 5 6 7 8 9 k 3 第乙個人出列後的序列為 0 1 3 4 5 6 7 8 9 即 3 4 5 6 7 8 9 0 1 我們把該式轉化為 ...

約瑟夫環非遞迴演算法分析

joseph問題描述 n個人 編號0 n 1 從0開始報數,報到 m 1 的退出,剩下的人繼續從0開始報數。求勝利者的編號。求解思路 我們知道第乙個人 編號一定是m n 1 出列之後,剩下的n 1個人組成了乙個新的約瑟夫環 以編號為k m n的人開始 k k 1 k 2 n 2,n 1,0,1,2,...

約瑟夫環非遞迴演算法分析

joseph問題描述 n個人 編號0 n 1 從0開始報數,報到 m 1 的退出,剩下的人繼續從0開始報數。求勝利者的編號。求解思路 我們知道第乙個人 編號一定是m n 1 出列之後,剩下的n 1個人組成了乙個新的約瑟夫環 以編號為k m n的人開始 k k 1 k 2 n 2,n 1,0,1,2,...