算法之約瑟夫問題

把我上學(xué)時(shí)候在csdn上的筆記搬過來了

經(jīng)典的約瑟夫問題

題目:假設(shè)下標(biāo)從0開始,0绍豁,1歇式,2 .. n-1共n個(gè)人驶悟,從1開始報(bào)數(shù),報(bào)到m則此人從環(huán)中退出材失,下一個(gè)人重新從1開始報(bào)數(shù)痕鳍,以此類推,問最后剩下的一個(gè)人的編號是多少龙巨?

分析:
看到這個(gè)題目笼呆,我想最簡單的思路就是寫個(gè)程序模擬這個(gè)過程,最終產(chǎn)生結(jié)果旨别。
首先我們需要一個(gè)長度為n的數(shù)組诗赌,每個(gè)位置有兩個(gè)狀態(tài)分別表示該處的人是否退出,可以選擇boolean型秸弛。需要一個(gè)變量i來移動反復(fù)遍歷數(shù)組铭若,變量s來計(jì)數(shù)是否達(dá)到m洪碳,還需要一個(gè)變量count來計(jì)數(shù)環(huán)內(nèi)到底還有幾個(gè)人,以終止遍歷奥喻。

算法如下:

public static int yueSe(int n, int m) {
        //true 表示退出 偶宫,false表示沒有退出
        boolean[] arr = new boolean[n];
        int i = 0;
        int s = 1;
        int count = n;
        while (count > 0) {
            i++;
            if (i > n - 1) {
                i = 0;
            }
            if (!arr[i]) {
                s++;
                if (s == m) {
                    s = 0;
                    arr[i] = true;
                    System.out.print(i+" ");
                    count--;
                }
            }
        }
        return i;
    }

但是這種算法我們分析出它每刪除一個(gè)元素循環(huán)就要進(jìn)行m次,那么總的時(shí)間復(fù)雜度就是O(mn) 环鲤,并不理想纯趋。題目只是要求我們求出最后一個(gè)人的編號,我們可以另辟蹊徑冷离。

我們知道第一個(gè)人(編號一定是(m-1)%n) 出列之后吵冒,剩下的n-1個(gè)人組成了一個(gè)新的約瑟夫環(huán)(以編號為k=m mod n的人開始):
k ,k+1西剥, k+2 … n-2, n-1, 0, 1, 2 , … 痹栖,k-2
我們把他們的編號做一下轉(zhuǎn)換:
k –> 0
k+1 –> 1
k+2 –> 2


k-2 –> n-2

那么變換之后問題變成了和原問題一樣的問題只是規(guī)模變成了n-1,照這個(gè)思路下去最終數(shù)組長度變?yōu)?瞭空,轉(zhuǎn)換之后的角標(biāo)為0揪阿;這時(shí)候只要我們倒著推0轉(zhuǎn)換前的角標(biāo)為x,x轉(zhuǎn)換前的角標(biāo)為x’,x’轉(zhuǎn)換前的角標(biāo)為x”咆畏,有靈感了沒有這么遞推的話只要我們遞歸n-1次即可得到我們想要的角標(biāo)南捂。

關(guān)鍵是這個(gè)遞推公式是什么呢?
我們可以先看正著遞推的思路旧找,假設(shè)當(dāng)前角標(biāo)為x那么改變后的角標(biāo)y為
y=(x+n-k)%n ,其中k=m
那么倒推得公式即為
x=(y+k)%n ,這里對于一般情況我們要理解n是刪除前的數(shù)組長度溺健。
算法如下:

public static int yueSe2(int n,int m){
        int f=0;
        for(int i=2;i<=n;i++){
            f=(f+m)%i;
        }
        return f;
    }

網(wǎng)易筆試題(約瑟夫問題變形)

題目:小明同學(xué)把1到n這n個(gè)數(shù)字按照一定的順序放入了一個(gè)隊(duì)列Q中。現(xiàn)在他對隊(duì)列Q執(zhí)行了如下程序:

while(!Q.empty())              //隊(duì)列不空钮蛛,執(zhí)行循環(huán)

{

    int x=Q.front();            //取出當(dāng)前隊(duì)頭的值x

    Q.pop();                 //彈出當(dāng)前隊(duì)頭

    Q.push(x);               //把x放入隊(duì)尾

    x = Q.front();              //取出這時(shí)候隊(duì)頭的值

    printf("%d\n",x);          //輸出x

    Q.pop();                 //彈出這時(shí)候的隊(duì)頭

}

做取出隊(duì)頭的值操作的時(shí)候鞭缭,并不彈出當(dāng)前隊(duì)頭。
小明同學(xué)發(fā)現(xiàn)魏颓,這段程序恰好按順序輸出了1,2,3,…,n×肜保現(xiàn)在小明想讓你構(gòu)造出原始的隊(duì)列,你能做到嗎甸饱?

這個(gè)題目雖然是取出一個(gè)放到隊(duì)列尾易结,刪除接下來一個(gè),但是仔細(xì)一想其實(shí)這個(gè)問題和約瑟夫問題是一樣的柜候,而且m=2搞动。但是這個(gè)題是要確定所有位置的出場順序,目前博主沒有找到O(n)的解法渣刷,不多做分析啦鹦肿,相信大家一看就懂,代碼如下

public static void answer(int n) {
        int[] arr = new int[n];
        int count = 0;
        int i = 0;
        int s = 1;
        while (count < n) {
            i++;
            if (i > n - 1) {
                i = 0;
            }
            if (arr[i] == 0) {
                s++;
            }
            if (s == 2) {
                s = 0;
                count++;
                arr[i] = count;
            }
        }
        for (int j = 0; j < n - 1; j++) {
            System.out.print(arr[j] + " ");
        }
        System.out.print(arr[n - 1]);
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末辅柴,一起剝皮案震驚了整個(gè)濱河市箩溃,隨后出現(xiàn)的幾起案子瞭吃,更是在濱河造成了極大的恐慌,老刑警劉巖涣旨,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件歪架,死亡現(xiàn)場離奇詭異,居然都是意外死亡霹陡,警方通過查閱死者的電腦和手機(jī)和蚪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來烹棉,“玉大人攒霹,你說我怎么就攤上這事〗矗” “怎么了催束?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長伏社。 經(jīng)常有香客問我抠刺,道長,這世上最難降的妖魔是什么摘昌? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任速妖,我火速辦了婚禮,結(jié)果婚禮上第焰,老公的妹妹穿的比我還像新娘买优。我一直安慰自己妨马,他們只是感情好挺举,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著烘跺,像睡著了一般湘纵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上滤淳,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天梧喷,我揣著相機(jī)與錄音,去河邊找鬼脖咐。 笑死铺敌,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的屁擅。 我是一名探鬼主播偿凭,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼派歌!你這毒婦竟也來了弯囊?” 一聲冷哼從身側(cè)響起痰哨,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎匾嘱,沒想到半個(gè)月后斤斧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡霎烙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年撬讽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吼过。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡锐秦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出盗忱,到底是詐尸還是另有隱情酱床,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布趟佃,位于F島的核電站扇谣,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏闲昭。R本人自食惡果不足惜罐寨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望序矩。 院中可真熱鬧鸯绿,春花似錦、人聲如沸簸淀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽租幕。三九已至舷手,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間劲绪,已是汗流浹背男窟。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贾富,地道東北人歉眷。 一個(gè)月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像颤枪,于是被迫代替她去往敵國和親汗捡。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容