記事ディレクトリ
トピック:60. k番目の順列
セット[1,2,3、...、n]を指定すると、そのすべての要素はn!個の順列を持ちます。
すべての順列をサイズ順にリストし、1つずつマークします。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"
ソース:LeetCode(LeetCode)
リンク:https ://leetcode-cn.com/problems/permutation-sequence
著作権はLeetCode が所有しています。商用転載については、正式な許可書にご連絡ください。非商用転載については、出典を明記してください。
基本的な考え方:dfs + pruning
この質問は、完全な配置と同様の考え方を使用していますが、この質問に合格する場合は少し変更する必要があります。1つは番号の位置を交換することで、もう1つはプルーニングすることです。
最初に完全配列のアイデアについて話しましょう:
- 完全な配置は、最初の番号と次の番号の完全な配置に相当します
- 次に、各番号を最初の位置に順番に入れ替え、その後ろにあるすべての番号を配置して、最終的な結果を取得します
改善が必要なこの質問の最初のポイント:
- ここで各番号を最初の番号と交換しないでください。この質問で必要な完全な配置の順序に準拠するには、番号を元のシーケンスから削除してから、最初の番号の位置に挿入する必要があります。(注:ここでの最初の位置とは、関数内のposの位置を指します)例:1234、4で始まる完全な配置が最初に表示されるときは4123ですが、前の完全な配置方法によると、最初に表示されるのは4231(1および4交換)、この扱いは間違っています!!!
この質問を改善する必要がある2番目の点:
- 剪定操作:k番目の順列を探していることがわかっているので、この数で始まる順列の数を使用して剪定を実行できます。
例:1234、9番目の順列を見つける必要があります。最初に1で始まる6(つまり、234の完全順列)、6 <9であるため、9番目の順列は1で始まってはならず、次の全体を見つける必要があります。 3番目の順列。
次に、2から始まる完全な順列を探します。6、6> 3がまだある場合、9番目の順列は2から始まります。同様に、次の各桁を順番に決定します。
class Solution {
public:
string cur = "";
int qn;
string getPermutation(int n, int k) {
string nums = "";
for(int i = 0; i < n; ++i){
nums += ((i + 1) + '0');
}
qn = n;
int cnt = k;
dfs(nums, 0, cnt);
return cur;
}
bool dfs(string nums, int pos, int &cnt){
if(cnt == 1){
cur = nums;
return true;
}
bool flag = false;
//第一个数字加上其后面数字的全排列
//依次将每一个数字放在第一位,对其后面的数字进行全排列
for(int i = pos; i < qn && !flag; ++i){
//剪枝
//计算以该数字开头的全排列的个数
int sum_pos = fun(qn - pos - 1);
if(sum_pos < cnt){
cnt -= sum_pos;
continue;
}
//将当前字符从字符串中删除,插入到pos指示的位置
string cur = nums;
char t = nums[i];
cur.erase(cur.begin() + i);
cur.insert(cur.begin() + pos, t);
flag = dfs(cur, pos + 1, cnt);
}
return flag;
}
int fun(int num){
int res = 1;
while(num){
res *= num;
num--;
}
return res;
}
};