LeetCode 約瑟夫環(動態規劃)

面試題62. 圓圈中最後剩下的數字

題目描述
在這裏插入圖片描述法一:鏈表模擬(超時)

直接模擬刪除的過程,比如開始的時候是從0位置開始遍歷,每隔m刪除一個數,當我們在依次遍歷m-1位置的同時,將它們依次移動到鏈表的末尾。當遍歷到m位置的時候就不添加到鏈表末尾而是直接刪除,重複此過程直到剩下最後一個數爲止。

 	int lastRemaining(int n, int m) {
        list<int> li;
        for(int i = 0; i < n; i++)
            li.push_back(i);
        while(li.size() != 1)
        {
            int cnt = m;
            while(cnt--)
            {
                if(cnt != 0)
                    li.push_back(li.front());
                li.pop_front();
            }
        }
        return li.front();
    }

法二:動態規劃(AC)

既然是動態歸化那我們肯定需要定義狀態、初始狀態和狀態轉移

狀態: 在這裏我們設狀態dp[i] 表示一共有i個數時最後剩下數的位置

初始狀態: 當狀態爲dp[0]顯然不管m爲多少最後一個數的位置就是0

狀態轉移: 狀態轉移就是當狀態爲dp[i]時怎麼過渡到dp[i+1],這裏根據狀態的含義我們知道dp[i]表示的是一共有i個數時最後剩下數的位置,dp[i+1]表示的是一共有i+1個數時最後剩下數的位置,其實很容易就能看出這兩個位置不就是剛好相差m嗎,因此狀態轉移方程爲 dp[i] = dp[i - 1] + m;

然後我們就可以愉快的寫出下面的代碼

    int lastRemaining(int n, int m) {
        int lastPos = 0;  // 記錄上一次最後被刪除數的位置
        for(int i = 2; i <= n; i++)
        {
            lastPos = (lastPos + m) % i;  // 由於lastPos可能會大於i所以這裏需要取模
        }
        return lastPos;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章