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),只使用常數個變數。
個人理解
數學解法:感覺就是不是我們的常規方法,一個特定的公式,反正就用這個公式能算出來。
公式:
f(N,M) = (f(N-1,M) + M) % N
,其中:N 表示 N 個數
M 表示 上面刪除的第 m 個數字
f(N,M) 表示 N 個數,每次刪除第 M 個數的時候,最終剩下的數的編號
f(N-1,M) 表示,N-1 個數,每次刪除第 M 個數的時候,最終剩下的數的編號
理解記住:我也很好奇怎麼得出這個公式是怎麼來的,但是我覺得理解記住這個公式更重要,知道可以用這種遞推公式得出也很重要。
手動模擬:我們來手動模擬一下上述問題求解過程。
【0,1,
2
,3,4】。第一輪我們刪除了第三個數字,也就是2
。下一個開頭數字為 3。【3,4,
0
,1】。第二輪我們刪除了第三個數字,也就是0
。下一個開頭數字為 1。【1,3,
4
】。第三輪我們刪除第三個數字,也就是4
.下一個開頭數字為 1。【1,3,
1
】。第四輪我們刪除第三個數字,也就是1
。因為只剩下兩個數字,為了構成個環,我們在後面補上一個1
,此時剩下最後一個資料3
,最終結果為3
。
公式驗證:我們再用上面的公式來驗證一下公式是否正確。注意:該公式得出來的結果是數字的下標(把上述看成一個陣列 array)
f(1,3)
:只有 1 個數,那這個數就是最終結果,它的下標位置為0
,即f(1,3)=0
。f(2,3) =(f(1,3)+3)% 2 = 1
:有 2 個數,剩下的數的下標位置為1
,即f(2,3)=1
。f(3,3) =(f(2,3)+3)% 3 = 1
:有 3 個數,剩下的數的下標位置為1
,即f(3,3)=2
。f(4,3) =(f(3,3)+3)% 4 = 0
:有 4 個數,剩下的數的下標位置為0
,即f(4,3)=0
。f(5,3) =(f(4,3)+3)% 5 = 3
:有 5 個數,剩下的數的下標位置為3
,即f(5,3)=3
。
公式的出來的結果同上面手動模擬的出來的結果一致,陣列 array[3]=3。我們再理解一下為什麼這個公式得出來的是陣列的下標。
問題一:假設我們已經知道了有 5 個數字的時候,最終留下來的數字是下標位置為 3 的數字,那下一輪只有 4 個數字的時候,留下來的數字的下標位置是多少?
- 其實,第一輪刪除第 3 個數字的時候,3 後面的數字都向前移動 3 位,最終留下來的數字也向前移動 3 位,也就是
0
。
- 其實,第一輪刪除第 3 個數字的時候,3 後面的數字都向前移動 3 位,最終留下來的數字也向前移動 3 位,也就是
問題二:假設我們知道了 4 個數字的時候,最終留下來的數字的下標為 0,那麼當數字有 5 個的時候,最終留下來的數字的下標是多少?
- 這個過程可以看做是上一個過程的逆過程,大家都往後移動 3 位,所以
f(5,3) =(f(4,3)+3) = 3
。不過有可能陣列越界,所以模上當前的數字的個數。即:f(5,3) =(f(4,3)+3)% 5 = 3
。
- 這個過程可以看做是上一個過程的逆過程,大家都往後移動 3 位,所以
問題三:現在有 N 個數字,刪除第 M 個數字,應該怎麼移動?
- 每刪除一個數字,下一個數字成為第一個數字,相當於把整個陣列前移 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
。
- 每刪除一個數字,下一個數字成為第一個數字,相當於把整個陣列前移 M 位。若已知 N-1 個數字的時候,最終留下來的數字的下標為
這可以解釋了為什麼這個公式求的是最終留下來的數字的下標,因為刪除數字會引起數字下標位置的移動。
為什麼遞推可以?環狀填充理解。這個理解還是很可以,無論刪除多少個,倆環最終剩下的部分都長得一樣,所以可以轉為遞推公式來理解。且滿足上述遞推公式。
遞推公式的起點和終點? 首先初始位置為
0
,然後從第二輪開始,所以要i=2
,到第 N 輪,所以要i<=N
。每次執行result=(result+m)%i
。其中 m 是要刪除的數,i 為當的輪數。
來源:力扣(LeetCode)
連結:leetcode-cn.com/problems/yuan-quan...
本作品採用《CC 協議》,轉載必須註明作者和本文連結