第k個排列(C++)
阿新 • • 發佈:2019-01-11
給出集合 [1,2,3,…,n]
,其所有元素共有 n! 種排列。
按大小順序列出所有排列情況,並一一標記,當 n = 3 時, 所有排列如下:
"123"
"132"
"213"
"231"
"312"
"321"
給定 n 和 k,返回第 k 個排列。
說明:
- 給定 n 的範圍是 [1, 9]。
- 給定 k 的範圍是[1, n!]。
示例 1:
輸入: n = 3, k = 3 輸出: "213"
示例 2:
輸入: n = 4, k = 9
輸出: "2314"
【解題思路】
先以n=4,k=9為例,看下圖:
有沒有發現什麼規律?
1.n!種排列中的順序可以分為(n!/n)組,其中每組的第一個數字都一樣;
2.通過k求出該序列落在第幾組,比如,上圖n=4,k=9,就落在第二組,那該序列的第一個元素就是陣列的第二個元素--2;
3.第一個元素確定後,把陣列的這個數摳掉,比如,上面2已經確定了,就把2扣掉,陣列就剩3個元素了---[1,3,4]。注意:摳掉後,陣列仍然要保持有序。
4.當第一個元素確定後,陣列就變成3個元素,k變成了3,即n=3,k=3。陣列為[1,3,4],再重複上面的步驟,就可求出第二個元素是3,在摳掉3。
問題關鍵在於怎麼計算下一次的落在第幾組和k。
#include"stdafx.h" #include<iostream> #include<string> #include<vector> using namespace std; int getgroup(int num, int k)//num為每個組元素個數; { if (k % num == 0) return k / num; else return k / num + 1; } int getk(int num, int k) { if (k < num) return k; else { if (k % num == 0) return num; else return k % num; } } string getPermutation(int n, int k) { if (n < 1) return ""; int count = 1;//n!總共排列數量 vector<int> vct; string res(""); for (int i = 1; i <= n; i++) { vct.push_back(i); } for (int i = 1; i <= n; i++) { count *= i; } while (n > 0) { //每組的個數 int num = count / n; //落在哪一組 int group = getgroup(num, k); //計算下一次的k值 k = getk(num, k); //結果追加到字串 res += vct[group - 1] + '0'; //下一次的序列總數 count /= n; //刪除元素 vct.erase(vct.begin() + group - 1); n--; } return res; } int main() { getPermutation(4, 9); getPermutation(3, 6); getPermutation(3, 1); getPermutation(3, 2); return 0; }
解釋一下:
1.n有序數放在vector,主要是刪除指定位置的元素好操作;
2.最核心的是求出group,因為知道group就知道給字串追加哪個數字了,
int getgroup(int num, int k)//num為每個組元素個數;
{
if (k % num == 0) return k / num;
else
return k / num + 1;
}
舉例:n=4,k=9
count = 24,共n=4組,每組num=6個序列,第9個應該落在 第(9 / 6+1)=2組上,所以就把當前陣列[1,2,3,4]的第二個(2)數追加到字串上,然後把 "2"從陣列中去掉,陣列變為[1,3,4].
需要注意的是:k能被num整除時是特殊處理,比如上面的例子(n=4,k=12)那麼group=12/2=2,就是在第二組,不需要加1了。
還有這裡k不會等於0,所以不用考慮k=0的情況。
3.本次的值追加到字串後,就需要計算下一次k的值
int getk(int num, int k)
{
if (k < num) return k;
else
{
if (k % num == 0)
return num;
else
return k % num;
}
}
如上圖,從n=4,k=9 變為 n=3,k=3;這是怎樣一個過程?