排列序列
题目描述:
出集合 [1,2,3,...,n],其所有元素共有 n! 种排列。按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:1 "123"2 "132"3 "213"4 "231"5 "312"6 "321"给定 n 和 k,返回第 k 个排列。
class Solution {
private int[] combination;
private boolean[] used;
private int[] cut;
private String result;
private String temp;
private int n;
private int k;
private int times;
private boolean end; // 提前终止标记
public String getPermutation(int n, int k) {
// 初始化
this.n = n;
this.k = k;
this.temp = "";
this.result = "";
this.combination = new int[n];
this.used = new boolean[n];
this.cut = new int[n];
this.cut[0] = 1;
this.combination[0] = 1;
for(int i = 1 ; i<n ; i++){
this.combination[i] = i+1;
this.cut[i] = cut[i-1]*(i+1);
}
int count = 0;
// 第一层剪枝
if(n-2>=0){
// 对n大于等于2的情况下进行剪枝
int a = k/cut[n-2];
// 下标特殊边界处理
for(int i = 1 ; i<=n ; i++){
if(i*cut[n-2] == k){
this.result += i;
for(int j = n ; j>0 ; j--){
if(j != i){
this.result += j;
}
}
return result;
}
}
used[a] = true;
temp += combination[a];
count ++;
times += a*cut[n-2];
}
// 深度搜索算法
DFS(count); // 当前已经使用的元素个数
return this.result;
}
private void DFS(int count){
if(count == this.n){
this.times++;
if(this.times == this.k){
this.end = true;
this.result = this.temp;
return;
}
return;
}
for(int i = 0 ; i<n && !this.end ; i++){
if(!used[i]){
temp += ""+combination[i];
used[i] = true;
DFS(count+1);
temp = temp.substring(0,temp.length() - 1);
used[i] = false;
}
}
}
}
这个题单纯地用DFS会超时,这里必须要用剪枝操作,利用数学规律,可以省略掉大部分不必要的运算时间,这里笔者只进行了第一层剪枝,即对第一个数确定做了剪枝,可以AC。