詳解基於C 實現約瑟夫環問題的三種解法

2022-09-25 01:18:12 字數 2574 閱讀 9440

目錄

什麼是約瑟夫環問題?

約瑟夫環問題在不同平台被"優化"描述的不一樣,例如在牛客劍指offer叫孩子們的遊戲,還有叫殺人遊戲,點名……最直接的感覺還是力扣上劍指offer62的描述:圓圈中最後剩下的數字。

問題描述:

0,1,,n-1這n個數字排成乙個圓圈,從數字0開始,每次從這個圓圈裡刪除第m個數字(刪除後從下乙個數字開始計數)。求出這個圓圈裡剩下的最後乙個數字。

例如,0、1、2、3、4這5個數字組成乙個圓圈,從數字0開始每次刪除第3個數字,則刪除的前4個數字依次是2、0、4、1,因此最後剩下的數字是3。

當然,這裡考慮m,n都是正常的資料範圍,其中

對於這個問題,你可能腦海中有了印象,想著小時候村里一群孩子坐在一起,從某個開始報數然後數到幾齣列,下乙個重新開始一直到最後乙個。

這個問題最本質其實就是迴圈鍊錶的問題,圍成乙個圈之後,就沒有結尾這就是乙個典型的迴圈鍊錶嘛!乙個乙個順序報數,那不就是鍊錶的遍歷列舉嘛!數到對應數字的出列,這不就是迴圈鍊錶的刪除嘛!

並且這裡還有非常方便的地方:

當然也有一些需要注意的地方

這樣,思路明確,直接開擼**:

class solution

node next;

}public int lastremaining(int n, int m)

else

head=head.next;

}但我們很多時候不會手動去寫乙個鍊錶模擬,我們會借助arraylist和linkedlist去模擬,如果使用linkedlist其底層也是鍊錶,使用arrautimoysyyrylist的話其底層資料結構是陣列。不過在使用list其**方法一致。

list可以直接知道長度,也可刪除元素,使用list的難點是乙個順序表怎們模擬成迴圈鍊錶?

咱們仔細思考:假設當前長度為n,數到第m個(通過上面分析可以求餘讓這個有效的m不大於n)刪除,在index位置刪除。那麼刪除後剩下的就是n-1長度,index位置就是表示第乙個計數的位置,我們可以通過求餘得知走下乙個刪除需要多少步,那麼下個位置怎麼確定呢?

你可以分類討論看看走的次數是否越界,但這裡有更巧妙的方法,可以直接求的下一次具體的位置,公式就是為:

index=(index+m-1)%(list.size());

因為index是從1計數,如果是迴圈的再往前m-1個就是真正的位置,但是這裡可以先假設先將這個有序集合的長度擴大若干倍,然後從index計數開始找到假設不迴圈的位置index2,最後我們將這個位置index2%(集合長度)即為真正的長度。

使用這個公式一舉幾得,既能把上面m過大迴圈過多的情況解決,又能找到真實的位置,就是將這個環先假設成線性的然後再去找到真的位置,如果不理解的話可以再看看這個圖:

這種情況的話大部分的oj是可以勉強過關的,面試官的層面也大概率差不多的,具體**為:

class solution

return list.get(0);}}

我們回顧上面的優化過程,上面用求餘可以解決m比n大很多很多的情況(即理論上需要轉很多很多圈的情況)。但是還可能存在n本身就很大的情況,無論是順序表arraylist還是鍊錶linkedlist去頻繁查詢、刪除都是很低效的。

所以聰明的人就開始從資料找一些規律或者關係。

先丟擲公式:

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

f(n,m)指n個人,報第m個編號出列最終編號

下面要認真看一下我的分析過程:程式設計客棧

我們舉個例子,有0 1 2 3 4 5 6 7 8 9十個數字,假設m為3,最後結果可以先記成f(10,3),即使我們不知道它是多少。

當進行第一次時候,找到元素2刪除,此時還剩9個元素,但起始位置已經變成元素3。等價成3 4 5 6 7 8 9 0 1這9個數字重寫開始找。

此時這個序列最終剩下的乙個值即為f(10,3),這個序列的值和f(9,3)不同,但是都是9個數且m等於3,所以其刪除位置是相同的,即演算法大體流程是一致的,只是各位置上的數字不一樣。所以我們需要做的事情是找找這個序列上和f(9,3)值上有沒有什麼聯絡。

尋找過程中別忘記兩點,首先可通過%符號對數字有效擴充,即我們可以將3 4 5 6 7 8 9 0 1這個序列看成(3,4,5,6,7,8,9,10,11)%10.這裡的10即為此時的n數值。

另外數值如果是連續的,那麼最終乙個結果的話是可以找到聯絡的(差值為乙個定製)。所以我們可以就找到f(10,3)和f(9,3)值之間結果的關係,可以看下圖:

所以f(10,3)的結果就可以轉化為f(9,3)的表達,後面也是同理:

f(10,3)=(f(9,3)+3)%10

f(9,3)=(f(8,3)+3)%9

f(2,3)=(f(1,3)+3)%2

f(1,3)=0

這樣,我們就不用模擬操作,可以直接從數值的關係找到遞推的關係,可以輕輕鬆鬆的寫下**:

class solution

}但是遞迴效率因為有個來回的規程,效率相比直接迭代差一些,也可從前往後迭代:

class solution

return value;}}

我想,通過本篇文章你應該掌握和理解了約瑟夫環問題,這種裸的約瑟夫環問題出現的概率很大,考察很頻繁,鍊錶模擬是根本思想,有序集合模擬鍊錶是提公升,而公式遞推才是最有學習價值的地方,如果你剛開始接觸不理解可以多看幾遍。

C 約瑟夫環問題詳解

有一家公司,這個公司有一位老闆和13名程式設計師,每天下班前老闆都會組織他們玩一次遊戲,遊戲的勝利者可以不加班,失敗者需要加班2小時。遊戲規則如下 一張圓桌共有13個座位,從1到13編號,遊戲開始前老闆會說出今天開始報數的座位編號start和淘汰序號k。然後13名程式設計師開始搶位置,每個位置只能容...

約瑟夫環問題詳解

講乙個比較有意思的故事 約瑟夫是猶太軍隊的乙個將軍,在反抗羅馬的起義中,他所率領的軍隊被擊潰,只剩下殘餘的部隊40餘人,他們都是寧死不屈的人,所以不願投降做叛徒。一群人表決說要死,所以用一種策略來先後殺死所有人。於是約瑟夫建議 每次由其他兩人一起殺死乙個人,而被殺的人的先後順序是由抽籤決定的,約瑟夫...

基本約瑟夫環問題詳解

本人水平有限,題解不到為處,請多多諒解 本蒟蒻謝謝大家 推薦部落格 傳送門 首先讓我們來看一下這一段 n 2 k1 n 2 n1 n1為當前序列的總人數,因為是迴圈的序列,k1 n 1可能大於總人數 至關重要,比如 我們已經知道當前的最後乙個出列的位置為f 設下一次最後乙個出列的位置為ans 則an...