約瑟夫環算法
問題: N我的編號爲1,2,……,N,圍成一個環,依次報數,每報到M時,殺掉那我的,求最後勝利者的編號。編程
換一下編號,如今假設有10我的編號爲a,b,c,d,e,f,g,h,i,j,M=3吧。數組
殺第一我的的結果以下數據結構
殺第二我的的時候至關於從d開始,結果以下code
最後咱們能夠知道d最終存活了下來,設f(n) = x 表示有n我的時存活下來的是x,這裏f(10)=d。blog
如今咱們來跟蹤一下d的位置變化遞歸
一開始殺第一我的時d的位置基礎
而後殺第二我的時d的位置im
看到這裏我想你應該什麼都看不出來,若是我此時問你若是隻有9我的那麼那我的存活的下標是多少你應該也是看不出來的。
這裏不是說你們笨,你們都是這樣子,一開始誰能反映的過來的啊。不用急聽我細細道來。鏈表
再看一下這個圖
咱們很容易就能夠得知最後一個是一個死人,死人是不會再被數一次的,那咱們就把最後一個死人刪掉吧。
那此時不就至關於只有9我的的狀況嗎
雖然字母順序對不上,可是若是隻看下標的話你應該可以說出9我的的時候下標是多少的人存活下來吧也就是下標爲0。
並且這個下標不是隨便來的,而是按照必定的規律出現的,也就是f(9) = f(10) - M,可能有人會問若是下標越界了咋辦啊。那還不簡單取模不就能夠了。f(n)有可能會是負數,負數取模可能比較抽象,那咱們轉換成正數取模吧(這一步是比較瓜熟蒂落的但願沒有把你困擾住) 也就是 f(10) = f(9)+M , 爲了預防越界也就是f(10) = (f(9)+M) %10; 爲何是和10取模而不是和9取模呢?這一點的是由於9我的時是由10我的經過移位再去掉最後一個死人後獲得的本質上仍是10我的,天然就是要和10取模,也能夠經過上面的圖,更好的理解這一點。
經過這個例子,想必你可以簡單的寫出遞歸式子了吧,也就是f(n) = (f(n-1)+M)%n。
全過程以下
代碼很簡單
public int f(int n,int m){ if(n==1) return 0; return (f(n-1,m)+m)%n; }
固然這題還有其餘解法,數組法和鏈表法,這些思惟量就少一些了。
若是以爲有收穫,不妨花個幾秒鐘點個贊,歡迎關注個人公衆號玩編程地碼農,目前專一寫數據結構與算法和計算機基礎等相關知識。