問題
集合[1,2,3……,n]共包含n!不同的排列,把他們從小到大排序可以得到:
"123"
"132"
"213"
"231"
"312"
"321"
現在給定和,找到第個全排列。
解析
回溯是解決全排列問題的最最最通用的解法,當然,同樣適用於該問題。但是用回溯解決該問題複雜度實在太高,而且這裏不需要求得所有的全排列,只需要求第個全排列,所以我們可以轉變一下思路。我們先看一下第個全排列有沒有什麼規律。
當n=3時,前兩個數是1開頭,中間兩個數是2開頭,最後面兩個數是3開頭。那麼當時,第個全排列的第一位是1;依次類推得到k的取值範圍和第一位對應的關係。
我們能不能按照這樣的規律繼續深入下去確定第二位,第三位? 答案是肯定的。假設我們確定了第一位數是1,那麼第二位數在2,3中選,如何選?同樣的,把k的範圍進一步縮小,縮小到是或者。問題來了,如何在代碼中體現這種範圍的縮小過程呢?我總不能寫一大堆判定語句吧?下圖詳細地給出瞭如何判斷第位的數字:
剩下的就是取商,判斷位置,然後更新更準確的位置,然後取商…
Java代碼
public String getPermutation(int n, int k) {
StringBuilder sb = new StringBuilder();
List<Integer> list = new LinkedList();
int sum = 1;
int i=1;
for(i=1;i<=n;i++){
sum*=i;
list.add(i);
}
i=i-1;
while(i>0){
sum = sum/i;
int temp = k/sum;
if(temp*sum==k) {
sb.append(list.get(temp-1));
list.remove(temp-1);
temp = temp-1;
}
else {
sb.append(list.get(temp));
list.remove(temp);
}
k = k - temp*sum;
i--;
}
return sb.toString();
}