解決約瑟夫環(huán)

本文鏈接:https://blog.csdn.net/m0_37907797/article/details/102990940

1马靠、方法一:數(shù)組

在大一第一次遇到這個(gè)題的時(shí)候,我是用數(shù)組做的蔼两,我猜絕大多數(shù)人也都知道怎么做甩鳄。方法是這樣的:

用一個(gè)數(shù)組來(lái)存放 1,2额划,3 … n 這 n 個(gè)編號(hào)妙啃,如圖(這里我們假設(shè)n = 6, m = 3)

image

然后不停著遍歷數(shù)組,對(duì)于被選中的編號(hào)俊戳,我們就做一個(gè)標(biāo)記揖赴,例如編號(hào) arr[2] = 3 被選中了,那么我們可以做一個(gè)標(biāo)記抑胎,例如讓 arr[2] = -1燥滑,來(lái)表示 arr[2] 存放的編號(hào)已經(jīng)出局的了。

image

然后就按照這種方法圆恤,不停著遍歷數(shù)組突倍,不停著做標(biāo)記,直到數(shù)組中只有一個(gè)元素是非 -1 的盆昙,這樣羽历,剩下的那個(gè)元素就是我們要找的元素了。我演示一下吧:

image

這種方法簡(jiǎn)單嗎淡喜?思路簡(jiǎn)單秕磷,但是編碼卻沒(méi)那么簡(jiǎn)單,臨界條件特別多炼团,每次遍歷到數(shù)組最后一個(gè)元素的時(shí)候澎嚣,還得重新設(shè)置下標(biāo)為 0疏尿,并且遍歷的時(shí)候還得判斷該元素時(shí)候是否是 -1。感興趣的可以動(dòng)手寫(xiě)一下代碼易桃,用這種數(shù)組的方式做褥琐,千萬(wàn)不要覺(jué)得很簡(jiǎn)單,編碼這個(gè)過(guò)程還是挺考驗(yàn)人的晤郑。

這種做法的時(shí)間復(fù)雜度是 O(n * m), 空間復(fù)雜度是 O(n);

2敌呈、方法二:環(huán)形鏈表

學(xué)過(guò)鏈表的人,估計(jì)都會(huì)用鏈表來(lái)處理約瑟夫環(huán)問(wèn)題造寝,用鏈表來(lái)處理其實(shí)和上面處理的思路差不多磕洪,只是用鏈表來(lái)處理的時(shí)候,對(duì)于被選中的編號(hào)诫龙,不再是做標(biāo)記析显,而是直接移除,因?yàn)閺逆湵硪瞥粋€(gè)元素的時(shí)間復(fù)雜度很低签赃,為 O(1)谷异。當(dāng)然,上面數(shù)組的方法你也可以采用移除的方式姊舵,不過(guò)數(shù)組移除的時(shí)間復(fù)雜度為 O(n)晰绎。所以采用鏈表的解決方法如下:

1、先創(chuàng)建一個(gè)環(huán)形鏈表來(lái)存放元素:


image

2括丁、然后一邊遍歷鏈表一遍刪除荞下,直到鏈表只剩下一個(gè)節(jié)點(diǎn),我這里就不全部演示了

image

代碼如下:
// 定義鏈表節(jié)點(diǎn)

class Node{
    int date;
    Node next;

    public Node(int date) {
        this.date = date;
    }
}

// 核心代碼

public static int solve(int n, int m) {
    if(m == 1 || n < 2)
        return n;
    // 創(chuàng)建環(huán)形鏈表
    Node head = createLinkedList(n);
    // 遍歷刪除
    int count = 1;
    Node cur = head;
    Node pre = null;//前驅(qū)節(jié)點(diǎn)
    while (head.next != head) {
        // 刪除節(jié)點(diǎn)
        if (count == m) {
            count = 1;
            pre.next = cur.next;
            cur = pre.next;
        } else {
            count++;
            pre = cur;
            cur = cur.next;
        }
    }
    return head.date;
}

static Node createLinkedList(int n) {
    Node head = new Node(1);
    Node next = head;
    for (int i = 2; i <= n; i++) {
        Node tmp = new Node(i);
        next.next = tmp;
        next = next.next;
    }
    // 頭尾串聯(lián)
    next.next = head;
    return head;
}

這種方法估計(jì)是最多人用的史飞,時(shí)間復(fù)雜度為 O(n * m),空間復(fù)雜度是 O(n)尖昏。

方法三:遞歸

其實(shí)這道題還可以用遞歸來(lái)解決,遞歸是思路是每次我們刪除了某一個(gè)士兵之后构资,我們就對(duì)這些士兵重新編號(hào)抽诉,然后我們的難點(diǎn)就是找出刪除前和刪除后士兵編號(hào)的映射關(guān)系。

我們定義遞歸函數(shù) f(n吐绵,m) 的返回結(jié)果是存活士兵的編號(hào)迹淌,顯然當(dāng) n = 1 時(shí),f(n, m) = 1己单。假如我們能夠找出 f(n唉窃,m) 和 f(n-1,m) 之間的關(guān)系的話纹笼,我們就可以用遞歸的方式來(lái)解決了纹份。我們假設(shè)人員數(shù)為 n, 報(bào)數(shù)到 m 的人就自殺。則剛開(kāi)始的編號(hào)為

1

m - 2

m - 1

m

m + 1

m + 2

n

進(jìn)行了一次刪除之后,刪除了編號(hào)為 m 的節(jié)點(diǎn)蔓涧。刪除之后件已,就只剩下 n - 1 個(gè)節(jié)點(diǎn)了,刪除前和刪除之后的編號(hào)轉(zhuǎn)換關(guān)系為:

刪除前 — 刪除后

… — …

m - 2 — n - 2

m - 1 — n - 1

m ---- 無(wú)(因?yàn)榫幪?hào)被刪除了)

m + 1 — 1(因?yàn)橄麓尉蛷倪@里報(bào)數(shù)了)

m + 2 ---- 2

… ---- …
新的環(huán)中只有 n - 1 個(gè)節(jié)點(diǎn)元暴。且刪除前編號(hào)為 m + 1, m + 2, m + 3 的節(jié)點(diǎn)成了刪除后編號(hào)為 1篷扩, 2, 3 的節(jié)點(diǎn)昨寞。

假設(shè) old 為刪除之前的節(jié)點(diǎn)編號(hào)瞻惋, new 為刪除了一個(gè)節(jié)點(diǎn)之后的編號(hào),則 old 與 new 之間的關(guān)系為 old = (new + m - 1) % n + 1援岩。

注:有些人可能會(huì)疑惑為什么不是 old = (new + m ) % n 呢?主要是因?yàn)榫幪?hào)是從 1 開(kāi)始的掏导,而不是從 0 開(kāi)始的享怀。如果 new + m == n的話,會(huì)導(dǎo)致最后的計(jì)算結(jié)果為 old = 0趟咆。所以 old = (new + m - 1) % n + 1.
這樣添瓷,我們就得出 f(n, m) 與 f(n - 1, m)之間的關(guān)系了,而 f(1, m) = 1.所以我們可以采用遞歸的方式來(lái)做值纱。代碼如下:

int f(int n, int m){
    if(n == 1)   return n;
    return (f(n - 1, m) + m - 1) % n + 1;
}

int f(int n, int m){
    return n == 1 ? n : (f(n - 1, m) + m - 1) % n + 1;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鳞贷,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子虐唠,更是在濱河造成了極大的恐慌搀愧,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疆偿,死亡現(xiàn)場(chǎng)離奇詭異咱筛,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)杆故,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)迅箩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人处铛,你說(shuō)我怎么就攤上這事饲趋。” “怎么了撤蟆?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵奕塑,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我枫疆,道長(zhǎng)爵川,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任息楔,我火速辦了婚禮寝贡,結(jié)果婚禮上扒披,老公的妹妹穿的比我還像新娘。我一直安慰自己圃泡,他們只是感情好碟案,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著颇蜡,像睡著了一般价说。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上风秤,一...
    開(kāi)封第一講書(shū)人閱讀 51,598評(píng)論 1 305
  • 那天鳖目,我揣著相機(jī)與錄音,去河邊找鬼缤弦。 笑死领迈,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的碍沐。 我是一名探鬼主播狸捅,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼累提!你這毒婦竟也來(lái)了尘喝?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤斋陪,失蹤者是張志新(化名)和其女友劉穎朽褪,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鳍贾,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鞍匾,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了骑科。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片橡淑。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖咆爽,靈堂內(nèi)的尸體忽然破棺而出梁棠,到底是詐尸還是另有隱情,我是刑警寧澤斗埂,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布符糊,位于F島的核電站,受9級(jí)特大地震影響呛凶,放射性物質(zhì)發(fā)生泄漏男娄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望模闲。 院中可真熱鬧建瘫,春花似錦、人聲如沸尸折。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)实夹。三九已至橄浓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間亮航,已是汗流浹背荸实。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留塞赂,地道東北人泪勒。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像宴猾,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子叼旋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

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