約瑟夫環問題是一個經典的數學問題,背景故事參考百度百科,其原始問題如下:
0,1,,n-1這n個數字排成一個圓圈,從數字0開始,每次從這個圓圈里刪除第m個數字。求出這個圓圈里剩下的最后一個數字。
比較直接的想法是通過鏈表模擬游戲,直到最后只剩一個元素,但這樣的時間復雜度是O(nm),顯然不行。類似問題通過數學方法找到規律會簡單的多,其實很多遞歸以及動態規划題目也是通過數學方法找遞推式即可簡單解出。
記上述問題的解為f(n,m)。則第一個被刪除的數為(m-1)%n。此時,轉化為由m%n開始的,規模為(n-1,m)的相同問題結構約瑟夫環問題。所以此問題可以通過遞歸來求解,但要知道每次迭代之后,新元素和就元素的一一對應關系。以第一次迭代為例:
把新元素編號記為x,舊元素編號記為y,那么新舊編號的對應公式為
y = (x + m) % n
由此可得
f(n,m) = (f(n-1,m) + m) % n n>1
f(1,m) = 0
public int lastRemaining(int n, int m) { int f = 0; for (int i = 2; i <= n; i++) { f = (f + m) % i; } return f; }
其中f是f(1,m)的解。