題目:
n個數字(0,1,…,n-1)形成一個圓圈,從數字0開始,
每次從這個圓圈中刪除第m個數字(第一個為當前數字本身,第二個為當前數字的下一個數字)。
當一個數字刪除后,從被刪除數字的下一個繼續刪除第m個數字。
求出在這個圓圈中剩下的最后一個數字。
我的思路:
這是個很經典的環形問題,最優的方案時間復雜度是O(n):先構建遞推公式,再使用循環或者遞歸都能輕松求解,
網上的教程很少能把這個遞推公式的由來描述清楚,所以我在這里加入我的一些理解。
由於我們要求解的是n個元素,第m個數字,要找到最后的一個數字,那么我在這里假設得到的結果是f(n,m),
假設我們已有數列為:
0 1 ... m-2 m-1 m ... n-1
刪除一次后得到的新數列是(注意題目條件->從被刪除數字的下一個繼續刪除):
m m+1 ... n-1 0 1 ... m-2 ①
很顯然,通過一次刪除后,問題規模從n變成了n-1,而f(n-1,m)所要求解的數列是:
0 1 ... m-2 m-1 m ... n-2 ②
很顯然,把數列②向左移動m就變成了①的解(注意①和②不完全相同,但是我們想要求的是第一個值,因為第一個值是刪除后剩下的數字),
考慮到“左加右減”的數學原理和環形的特征,得到遞推公式:
0 if n==1
f(n,m)={
(f(n-1,m)+m)%n if n>1
那么也就不難得到如下代碼:
int LastNumberOfCircle(int n, int m) { int last = 0; for(int i=2;i<=n;++i) { last = (last+m)%i; } return last; }
