問題描述
https://leetcode.com/problems/permutation-sequence/#/description
he set [1,2,3,…,n]
contains a total of n!
unique permutations.
By listing and labeling all of the permutations in order,
We get the following sequence (ie, for n = 3
):
"123"
"132"
"213"
"231"
"312"
"321"
Given n
and k
, return the kth
permutation sequence.
Note: Given n will be between 1
and 9
inclusive.
求n個數字組成的所有全排列字符串中的第k個字符串。
算法
因爲只要求1
個,所以可以按照全排列的規則,一個個數的求出每個位置的數字,而不需要將所有的全排列字符串列出來。
對於n
個字符組成的字符串{1,2,3,...,n}
,取第k
個數時,首先可以求出第一個數,即(k-1)/(n-1個數的排列個數)
。
比如n=3,k=4
時,全排列組合爲:
1
+{2,3}
的全排列2
+{1,3}
的全排列3
+{1,2}
的全排列
我們可以首先求出目標排序的第一個數字,即(k-1)/(兩個數的排列數) = (k-1)/2 = 3/2 = 1
,下標從0
開始,下標1
表示的數就是2
。
接下來,就是求出{1,3}
全排列中排在第 k-2=2
個位置上的數,方法同3
個字母時一樣,求出結果後爲 231
。
所以,可以一層一層的求出第k
個順序的字符串。
時間複雜度爲O(N)
。
一開始是以遞歸形式寫的算法,相對容易理解,但速度慢,所以又寫了循環版本的。
代碼
循環版本
public String getPermutation(int n, int k) {
char[] nums = new char[]{'1','2','3','4','5','6','7','8','9'};
String tmp = "";
for(int i=0;i<n;i++) {
tmp += nums[i];
}
StringBuffer s = new StringBuffer(tmp);
String r = "";
while(k>0&&!s.toString().equals("")) {
// 計算 (n-1)的排列個數cnt
int cnt = 1, i = s.length()-1;
while(i > 1) {
cnt*=i;
i-=1;
}
int pos = (k-1)/cnt;
r += s.charAt(pos);
s = s.deleteCharAt(pos);
k -= pos * cnt;
}
return r;
}
遞歸版本
public String getPermutation1(int n, int k) {
char[] nums = new char[]{'1','2','3','4','5','6','7','8','9'};
String s = "";
for(int i=0;i<n;i++) {
s += nums[i];
}
return fun(new StringBuffer(s), k);
}
public String fun(StringBuffer s, int k) {
if(k<0 || s.toString().equals("")) return "";
int cnt = 1, tmp = s.length()-1;
while(tmp > 1) {
cnt*=tmp;
tmp-=1;
}
int pos = (k-1)/cnt;
return s.charAt(pos) + fun(s.deleteCharAt(pos), k - pos*cnt);
}
LeetCode解題代碼倉庫:https://github.com/zgljl2012/leetcode-java