標籤:style blog http io color ar sp for div
題目:給定數字n,然後將1到n的第k個字典序排列找出來,例如3的時候有所有字典序為:
"123" "132" "213" "231" "312" "321" 那麼第2個就是“132”,返回這個字串。
記得之前有做過輸出所有可能的排序,在Permutation中,有興趣還可以看看。所以很直觀的就是複製那題的代碼然後返回第k個就完事了。因為只要一分鐘,所以我試了一下,果斷是不行啊,提示逾時,那題是用遞迴做的。所以我們肯定是有方法不用求所有的啊。然後我就開始從數學角度進入探索了。發現和(n-1)!有巧妙的關係,就是用k-1除以(n-1)!再加一(但看下標的話不用加1)之後的值其實就是第k個排列中的第一個數。然後我也想到了用k減去相應的數,然後再計算接下去的是什麼數,但是後面的數字亂掉了,因為不是按照順序了。比如如果第一個數是2,那麼後面就是1,3了,所以我沒想到用k可以表示它的方法。其實就差一步就做出來了。哎。原來可以按下標輸出,不用找數字和k的關係,而是記錄下標和k的關係。看了這個大神的。覺得好贊。記錄下:
思路:
n個數的的第k個排列為:
a1, a2, a3,...an;
接下來我們一個一個數的選取,如何確定第一個數應該是哪一個呢?選取第一個數後剩下全排列的個數為(n-1)! 所以選取的第一個數應該為第
K1 = k;
a1 = K1/(n-1)!位元字
同理當選完a1後只剩下n-1個數字,在確定第二個數應該選擇哪個.
a2 = K2 / (n-2)!
K2 = K1 % (n-1)!
........
a(n-1) = K(n-1) / 1!
K(n-1) = k(n-2) % 2!
an = K(n-1)
代碼:
class Solution { public: string getPermutation(int n, int k) { vector<int> num(n, 0); int perm_sum = 1; for(size_t i = 0; i < n; ++i) { num[i] = i + 1; perm_sum *= (i + 1); } string ret; //因為數組是從0到n-1的 所以基數從 0到k-1 --k; for(size_t i = 0; i < n; ++i) { perm_sum = perm_sum / (n - i); int selected = k / perm_sum; ret.push_back(num[selected] + ‘0‘); //選擇一個數後重新構造剩下的數組 for(size_t j = selected; j < n - i - 1; ++j) num[j] = num[j + 1]; k = k % perm_sum; } return ret; } };
我覺得這個妙在階乘只求了一次,然後用後面的數覆蓋已經選出來的數,即數組往前,這樣每次都按照下標0開始即可。
leetcode Permutation Sequence