[每日一題] 第四題:圓圈中最後剩下的數字

DRose發表於2020-07-28

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

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

方法一:公式法

程式碼

class Solution {
    public int lastRemaining(int n, int m) {
        int ans = 0;
        // 最後一輪剩下2個人,所以從2開始反推
        for (int i = 2; i <= n; i++) {
            ans = (ans + m) % i;
        }
        return ans;
    }
}

複雜度

  • 時間複雜度:O(n),需要求解的函式值有 n 個。

  • 空間複雜度:O(1),只使用常數個變數。

個人理解

  1. 數學解法:感覺就是不是我們的常規方法,一個特定的公式,反正就用這個公式能算出來。

  2. 公式f(N,M) = (f(N-1,M) + M) % N,其中:

    1. N 表示 N 個數

    2. M 表示 上面刪除的第 m 個數字

    3. f(N,M) 表示 N 個數,每次刪除第 M 個數的時候,最終剩下的數的編號

    4. f(N-1,M) 表示,N-1 個數,每次刪除第 M 個數的時候,最終剩下的數的編號

  3. 理解記住:我也很好奇怎麼得出這個公式是怎麼來的,但是我覺得理解記住這個公式更重要,知道可以用這種遞推公式得出也很重要。

  4. 手動模擬:我們來手動模擬一下上述問題求解過程。

    1. 【0,1,2,3,4】。第一輪我們刪除了第三個數字,也就是 2下一個開頭數字為 3

    2. 【3,4,0,1】。第二輪我們刪除了第三個數字,也就是 0下一個開頭數字為 1

    3. 【1,3,4】。第三輪我們刪除第三個數字,也就是 4.下一個開頭數字為 1

    4. 【1,3,1】。第四輪我們刪除第三個數字,也就是 1。因為只剩下兩個數字,為了構成個環,我們在後面補上一個 1,此時剩下最後一個資料 3,最終結果為 3

  5. 公式驗證:我們再用上面的公式來驗證一下公式是否正確。注意:該公式得出來的結果是數字的下標(把上述看成一個陣列 array)

    1. f(1,3):只有 1 個數,那這個數就是最終結果,它的下標位置為 0,即 f(1,3)=0

    2. f(2,3) =(f(1,3)+3)% 2 = 1:有 2 個數,剩下的數的下標位置為 1,即 f(2,3)=1

    3. f(3,3) =(f(2,3)+3)% 3 = 1:有 3 個數,剩下的數的下標位置為 1,即 f(3,3)=2

    4. f(4,3) =(f(3,3)+3)% 4 = 0:有 4 個數,剩下的數的下標位置為 0,即 f(4,3)=0

    5. f(5,3) =(f(4,3)+3)% 5 = 3:有 5 個數,剩下的數的下標位置為 3,即 f(5,3)=3

  6. 公式的出來的結果同上面手動模擬的出來的結果一致,陣列 array[3]=3。我們再理解一下為什麼這個公式得出來的是陣列的下標。

  7. 問題一:假設我們已經知道了有 5 個數字的時候,最終留下來的數字是下標位置為 3 的數字,那下一輪只有 4 個數字的時候,留下來的數字的下標位置是多少?

    1. 其實,第一輪刪除第 3 個數字的時候,3 後面的數字都向前移動 3 位,最終留下來的數字也向前移動 3 位,也就是 0
  8. 問題二:假設我們知道了 4 個數字的時候,最終留下來的數字的下標為 0,那麼當數字有 5 個的時候,最終留下來的數字的下標是多少?

    1. 這個過程可以看做是上一個過程的逆過程,大家都往後移動 3 位,所以 f(5,3) =(f(4,3)+3) = 3。不過有可能陣列越界,所以模上當前的數字的個數。即:f(5,3) =(f(4,3)+3)% 5 = 3
  9. 問題三:現在有 N 個數字,刪除第 M 個數字,應該怎麼移動?

    1. 每刪除一個數字,下一個數字成為第一個數字,相當於把整個陣列前移 M 位。若已知 N-1 個數字的時候,最終留下來的數字的下標為 f(N-1,M),則當數字個數為 N 個的時候,最終留下來的數字就要後移 M 位,即 f(N,M) = f(N-1,M) + M。因為有可能陣列越界,所以要模上 N。即:f(N,M) = (f(N-1,M) + M) % N
  10. 這可以解釋了為什麼這個公式求的是最終留下來的數字的下標,因為刪除數字會引起數字下標位置的移動。

  11. 為什麼遞推可以?環狀填充理解。這個理解還是很可以,無論刪除多少個,倆環最終剩下的部分都長得一樣,所以可以轉為遞推公式來理解。且滿足上述遞推公式。

  12. 遞推公式的起點和終點? 首先初始位置為 0,然後從第二輪開始,所以要 i=2,到第 N 輪,所以要 i<=N。每次執行 result=(result+m)%i。其中 m 是要刪除的數,i 為當的輪數。

來源:力扣(LeetCode)

連結:leetcode-cn.com/problems/yuan-quan...

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章