https://leetcode.com/problems/permutation-sequence/
X.
the permutations with the same first number are in a group. you will realize there is
n groups, each of (n−1)! numbers. The permutations in each group are sorted as they are as a universal group. So our algorithm can work as follows: find which group the k-th permutation belongs to, extract the common first number from the list of numbers and append it to the construction of the permutation, and iteratively find within that group the (((k−1)%(n−1)!)+1)-th permutation.
From http://fisherlei.blogspot.com/2013/04/leetcode-permutation-sequence-solution.html
那么这里,我们把a1去掉,那么剩下的permutation为
a2, a3, .... .... an, 共计n-1个元素。 n-1个元素共有(n-1)!组排列,那么这里就可以知道
设变量K1 = K
a1 = K1 / (n-1)!
同理,a2的值可以推导为
a2 = K2 / (n-2)!
K2 = K1 % (n-1)!
.......
a(n-1) = K(n-1) / 1!
K(n-1) = K(n-2) /2!
an = K(n-1)
https://segmentfault.com/a/1190000003766760
http://blog.csdn.net/fightforyourdream/article/details/17483553
http://simpleandstupid.com/2014/10/29/permutation-sequence-leetcode-%E8%A7%A3%E9%A2%98%E7%AC%94%E8%AE%B0/
The best way to approach the problem is to divide and conquer:
let's start with numbers 1, 2, 3, 4, and we can divide the sequences into 4 groups each starts with 1, 2, 3, 4, the number of sequences in each are 3!, k/3! will decide which group the kth sequence belongs to, saying k=9, k/3! = 1, so kth sequence belongs with group starts with 2.
now we have 1,3,4 and we should look for k%3!=9%6=3th sequence in this set
And we can use recursion to do divide and conquer work.
public static List<Integer> permutationByRank(int n, int k){
//prepare the set
List<Integer> list = new ArrayList<Integer>();
for(int i=1; i<=n; i++)
list.add(i);
//calculate the group size
int size = factor(n-1);
return permuByRankUtil(list, k-1, size);
}
/*
* here k starts at 0 to n!-1 for easy computing purpose
*/
public static List<Integer> permuByRankUtil(List<Integer> nums, int k, int f){
int size = nums.size();
//base case
if(size==1)
return nums;
else{
//decide group index
int index = k/f;
int first = nums.remove(index);
List<Integer> re = permuByRankUtil(nums, k%f, f/(size-1));
re.add(0, first);
return re;
}
}
http://www.zrzahid.com/k-th-permutation-sequence/
https://discuss.leetcode.com/topic/15592/java-solution-with-o-1-space-modified-from-the-solution-for-permutation-1
Read full article from LeetCode - Permutation Sequence | Darren's Blog
The 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):
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.
X.
上面的算法都是逐个的求排列,有没有什么方法不是逐个求,而是直接构造出第k个排列呢?我们以n = 4,k = 17为例,数组src = [1,2,3,...,n]。
第17个排列的第一个数是什么呢:我们知道以某个数固定开头的排列个数 = (n-1)! = 3! = 6, 即以1和2开头的排列总共6*2 = 12个,12 < 17, 因此第17个排列的第一个数不可能是1或者2,6*3 > 17, 因此第17个排列的第一个数是3。即第17个排列的第一个数是原数组(原数组递增有序)的第m = upper(17/6) = 3(upper表示向上取整)个数。
第一个数固定后,我们从src数组中删除该数,那么就相当于在当前src的基础上求第k - (m-1)*(n-1)! = 17 - 2*6 = 5个排列,因此可以递归的求解该问题。
the permutations with the same first number are in a group. you will realize there is
From http://fisherlei.blogspot.com/2013/04/leetcode-permutation-sequence-solution.html
那么这里,我们把a1去掉,那么剩下的permutation为
a2, a3, .... .... an, 共计n-1个元素。 n-1个元素共有(n-1)!组排列,那么这里就可以知道
设变量K1 = K
a1 = K1 / (n-1)!
同理,a2的值可以推导为
a2 = K2 / (n-2)!
K2 = K1 % (n-1)!
.......
a(n-1) = K(n-1) / 1!
K(n-1) = K(n-2) /2!
an = K(n-1)
In order to grow the tree, every time start the first unfixed element in each node, generate child nodes by swapping the first element with every other element. The leave node are those do not have element to swap.
Let’s start looking at the 2nd level. There are n 2nd nodes, each subtree of them has (n-1)! children. (there are n! permutation in total). So which 2nd level subtree the kth permutation locate in? We can find it by computing k / (n-1)!. Say it is the ith subtree, then we get to ith subtree and set k = k % (n-1)!. Do so recursively to search the subtree until we get the leave node.
https://discuss.leetcode.com/topic/17348/explain-like-i-m-five-java-solution-in-o-n
https://discuss.leetcode.com/topic/18736/my-o-n-java-solution
https://discuss.leetcode.com/topic/5081/an-iterative-solution-for-reference
https://discuss.leetcode.com/topic/18736/my-o-n-java-solutionhttps://discuss.leetcode.com/topic/18736/my-o-n-java-solution
https://discuss.leetcode.com/topic/5081/an-iterative-solution-for-reference
public String getPermutation(int n, int k) {
int pos = 0;
List<Integer> numbers = new ArrayList<>(); // use linkedlist
int[] factorial = new int[n+1];
StringBuilder sb = new StringBuilder();
// create an array of factorial lookup
int sum = 1;
factorial[0] = 1;
for(int i=1; i<=n; i++){
sum *= i;
factorial[i] = sum;
}
// factorial[] = {1, 1, 2, 6, 24, ... n!}
// create a list of numbers to get indices
for(int i=1; i<=n; i++){
numbers.add(i);
}
// numbers = {1, 2, 3, 4}
k--;
for(int i = 1; i <= n; i++){
int index = k/factorial[n-i];
sb.append(String.valueOf(numbers.get(index)));
numbers.remove(index);
k-=index*factorial[n-i];
}
return String.valueOf(sb);
}
public String getPermutation(int n, int k) {
StringBuilder sb = new StringBuilder();
ArrayList<Integer> num = new ArrayList<Integer>();
int fact = 1;
for (int i = 1; i <= n; i++) {
fact *= i;
num.add(i);
}
for (int i = 0, l = k - 1; i < n; i++) {
fact /= (n - i);
int index = (l / fact);
sb.append(num.remove(index));
l -= index * fact;
}
return sb.toString();
}
static int[] facts = new int[10];
static{
facts[1] = 1;
for (int i=2;i<=9;i++){
facts[i] = facts[i-1]*i;
}
}
public String getPermutation(int n, int k) {
StringBuilder s = new StringBuilder();
List<Integer> digits = new LinkedList<Integer>();
for (int i=1;i<=n;i++){
digits.add(i);
}
k = k-1; //make zero based;
while (k>0 && digits.size()>1){//k==0 means remaining digits in the list are ordered.
int segmentLength = facts[digits.size()-1];
int index = k/segmentLength;
k = k%segmentLength; //calculate new k
s.append(digits.remove(index));
}
for (int i:digits){//add remaining digits
s.append(i);
}
return s.toString();
}
https://segmentfault.com/a/1190000003766760
由于我们只要得到第K个全排列,而不是所有全排列,我们不一定要将所有可能都搜索一遍。根据全排列顺序的性质,我们可以总结出一个规律:假设全排列有n个数组成,则第k个全排列的第一位是k/(n-1)!。为了更形象一点,举例如下:
123
132
213
231
312
321
在这种情况下,第一个数字每2!=2个情况就改变一次,假设求第6个排列,我们先将其减1,方便整除运算,然后5/2=2。对于第一位,我们有三种可选数字1、2、3,所以5/2=2意味着我们选择第3个数字,也就是3(如果商是s,则选第s+1个数字)。然后将5%2得到1,这个1就是下一轮的k。
这里有一个技巧,就是用一个列表将1到n存起来,每选用一个数就是移出那个数,就能保证不选重复数字的同时,其顺序也是一样的。
public String getPermutation(int n, int k) {
int mod = 1;
List<Integer> candidates = new ArrayList<Integer>();
// 先得到n!和候选数字列表
for(int i = 1; i <= n; i++){
mod = mod * i;
candidates.add(i);
}
// 将k先减1方便整除
k--;
StringBuilder sb = new StringBuilder();
for(int i = 0; i < n ; i++){
mod = mod / (n - i);
// 得到当前应选数字的序数
int first = k / mod;
// 得到用于计算下一位的k
k = k % mod;
sb.append(candidates.get(first));
// 在列表中移出该数字
candidates.remove(first);
}
return sb.toString();
}
public String getPermutation(int n, int k) {
// Create a list of 1, 2, ..., n, and compute the number of permutations as "groupSize"
List<Integer> list = new LinkedList<Integer>();
int groupSize = 1;
for (int i = n; i >= 1; i--) {
list.add(0, i);
groupSize *= i;
}
// Invalid k
if (k > groupSize)
return null;
// Construct the k-th permutation with a list of n numbers
// Idea: group all permutations according to their first number (so n groups, each of
// (n-1)! numbers), find the group where the k-th permutation belongs, remove the common
// first number from the list and append it to the resulting string, and iteratively
// construct the (((k-1)%(n-1)!)+1)-th permutation with the remaining n-1 numbers
StringBuilder builder = new StringBuilder();
while (n > 0) {
groupSize /= n;
int groupIndex = (k-1) / groupSize;
builder.append(list.remove(groupIndex));
n--;
k = ((k-1) % groupSize) + 1;
}
return builder.toString();
}
http://www.lifeincode.net/programming/leetcode-permutation-sequence-java/
Another way is to calculate every digit. For example, assuming we are going to solve the problem when n = 3 and k = 5. In fact, because k starts from 1, we need to subtract 1 from it to make it starting from 0. So we are going to find the permutation 4 now. To calculate the first digit, we can calculate it by k % (n – 1)! = 4 / 2! = 2, which is the position of 3 in array [1,2,3]. Now we need to delete 3 from the array, so the array becomes [1, 2]. And k should become 4 % 2! = 0. Now we calculate k / (n – 2)! = 0 / 1 = 0, which is the position of 1 in array [1, 2]. So the second digit should be 1. We need to delete 1 from the array. And there is only one entry left in the array. So the final digit should be 2. Finally we get the permutation: 312.
public String getPermutation(int n, int k) {
int t = 1;
List<Integer> numbers = new ArrayList<>(n);
for (int i = 1; i <= n; i++) {
t = t * i;
numbers.add(i);
}
t /= n;
k--;// 对k减一,因为现在index是从[0,n-1]而不是[1,n]
StringBuilder sb = new StringBuilder();
for (int i = n - 1; i >= 1; i--) {
int p = k / t;
int np = numbers.get(p);
sb.append(String.valueOf(np));
numbers.remove(p);
k %= t;
t /= i;
}
sb.append(String.valueOf(numbers.get(0)));
return sb.toString();
}
http://www.programcreek.com/2013/02/leetcode-permutation-sequence-java/public String getPermutation(int n, int k) { // initialize all numbers ArrayList<Integer> numberList = new ArrayList<Integer>(); for (int i = 1; i <= n; i++) { numberList.add(i); } // change k to be index k--; // set factorial of n int mod = 1; for (int i = 1; i <= n; i++) { mod = mod * i; } String result = ""; // find sequence for (int i = 0; i < n; i++) { mod = mod / (n - i); // find the right number(curIndex) of int curIndex = k / mod; // update k k = k % mod; // get number according to curIndex result += numberList.get(curIndex); // remove from list numberList.remove(curIndex); } return result.toString(); }
public String getPermutation(int n, int k) { boolean[] output = new boolean[n]; StringBuilder buf = new StringBuilder(""); int[] res = new int[n]; res[0] = 1; for (int i = 1; i < n; i++) res[i] = res[i - 1] * i; for (int i = n - 1; i >= 0; i--) { int s = 1; while (k > res[i]) { s++; k = k - res[i]; } for (int j = 0; j < n; j++) { if (j + 1 <= s && output[j]) { s++; } } output[s - 1] = true; buf.append(Integer.toString(s)); } return buf.toString(); }Also refer to http://swiyu.wordpress.com/2012/10/11/find-all-permutation-find-kth-permutation/
http://simpleandstupid.com/2014/10/29/permutation-sequence-leetcode-%E8%A7%A3%E9%A2%98%E7%AC%94%E8%AE%B0/
public
String getPermutation(
int
n,
int
k) {
// initialize all numbers
ArrayList<Integer> numberList =
new
ArrayList<Integer>();
for
(
int
i =
1
; i <= n; i++) {
numberList.add(i);
}
// change k to be index
k--;
// set factorial of n
int
mod =
1
;
for
(
int
i =
1
; i <= n; i++) {
mod = mod * i;
}
String result =
""
;
// find sequence
for
(
int
i =
0
; i < n; i++) {
mod = mod / (n - i);
// find the right number(curIndex) of
int
curIndex = k / mod;
// update k
k = k % mod;
// get number according to curIndex
result += numberList.get(curIndex);
// remove from list
numberList.remove(curIndex);
}
return
result.toString();
}
public String getPermutation(int n, int k) { StringBuilder sb = new StringBuilder(); boolean[] used = new boolean[n]; k = k - 1; int factor = 1; for (int i = 1; i < n; i++) { factor *= i; } for (int i = 0; i < n; i++) { int index = k / factor; k = k % factor; for (int j = 0; j < n; j++) { if (used[j] == false) { if (index == 0) { used[j] = true; sb.append((char) ('0' + j + 1)); break; } else { index--; } } } if (i < n - 1) { factor = factor / (n - 1 - i); } } return sb.toString(); }
X. RECURSTION
http://www.tangjikai.com/algorithms/leetcode-60-permutation-sequence
https://discuss.leetcode.com/topic/25165/another-solution-in-java-with-explanation-no-loop-no-swap-easy-understanding-200ms
X. DFS - not efficient
http://xiaochongzhang.me/blog/?p=693
http://www.tangjikai.com/algorithms/leetcode-60-permutation-sequence
class Solution:
# @param {integer} n
# @param {integer} k
# @return {string}
def getPermutation(self, n, k):
return self.helper([x + 1 for x in range(n)], n, k)
def helper(self, nums, n, k):
if n == 1:
return str(nums[0])
i = (k - 1) / math.factorial(n - 1)
return str(nums[i]) + self.helper(nums[:i] + nums[i + 1:], n - 1, (k - 1) % math.factorial(n - 1) + 1)
Complexity:
O(n^2) time
O(1) space
O(n^2) time
O(1) space
https://discuss.leetcode.com/topic/25165/another-solution-in-java-with-explanation-no-loop-no-swap-easy-understanding-200ms
public String getPermutation(int n, int k) {
List<Integer> participate = new ArrayList<>(n);
if (n <= 1) {
return "1";
}
for (int i = 1; i <= n; i++) {
participate.add(i);//build an initial list
}
return recur(n, k - 1, participate, new StringBuilder(n));//k-1 for get element from list
}
private String recur(int n, int k, List<Integer> participate, StringBuilder sb) {
if (n == 2) {
sb.append(participate.get(k));
participate.remove(k);
sb.append(participate.get(participate.size() - 1));
return sb.toString();
}
int x = fac(n); // x: sequence length Example: n = 5, there are 5 sequences start with 1 to 5, each sequence has 24 items
int i = k / x; // i: which sequence the search k it belong. Example: n=4 k=8, i=(8-1)/6=1. so the start number should be 2
sb.append(participate.get(i));
participate.remove(i);
return recur(n - 1, k % x, participate, sb);
}
private int fac(int n) {
int sum = 1;
for (int i = 1; i < n; i++) {
sum *= i;
}
return sum;
}
X. DFS - not efficient
http://xiaochongzhang.me/blog/?p=693
https://simpleandstupid.com/2014/10/29/permutation-sequence-leetcode-%E8%A7%A3%E9%A2%98%E7%AC%94%E8%AE%B0/
http://www.cnblogs.com/TenosDoIt/p/3721918.html
第一,DFS递归遍历所有可能,然后累加计算,直至到K为止
int
count =
0
;
String ret =
""
;
char
[] dic = {
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
'8'
,
'9'
};
public
String getPermutation(
int
n,
int
k) {
StringBuilder s =
new
StringBuilder();
int
[] visited =
new
int
[n];
dfs(n, k, s,
0
, visited);
return
ret;
}
public
void
dfs(
int
n,
int
k, StringBuilder s,
int
deep,
int
[] visited){
if
(deep == n){
count++;
if
(count == k){
ret = s.toString();
return
;
}
}
for
(
int
i =
0
; i < n; i++){
if
(visited[i] ==
0
){
s.append(dic[i]);
visited[i] =
1
;
dfs(n, k, s, deep+
1
, visited);
s.deleteCharAt(s.length()-
1
);
visited[i] =
0
;
}
}
}
int
count =
0
;
String ret =
""
;
char
[] dic = {
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
'8'
,
'9'
};
public
String getPermutation(
int
n,
int
k) {
StringBuilder s =
new
StringBuilder();
int
[] visited =
new
int
[n];
dfs(n, k, s,
0
, visited);
return
ret;
}
public
void
dfs(
int
n,
int
k, StringBuilder s,
int
deep,
int
[] visited){
if
(deep == n){
count++;
if
(count == k){
ret = s.toString();
return
;
}
}
for
(
int
i =
0
; i < n; i++){
if
(visited[i] ==
0
){
s.append(dic[i]);
visited[i] =
1
;
dfs(n, k, s, deep+
1
, visited);
s.deleteCharAt(s.length()-
1
);
visited[i] =
0
;
}
}
}
public static String getPermutation2(int n, int k) { kth = k; StringBuilder done = new StringBuilder(); StringBuilder rest = new StringBuilder(); for(int i=1; i<=n; i++){ rest.append(i); } rec(done, rest); return save; } public static void rec(StringBuilder done, StringBuilder rest){ if(rest.length() == 0){ kth--; if(kth == 0){ save = done.toString(); } return; } for(int i=0; i<rest.length(); i++){ char c = rest.charAt(i); rest.deleteCharAt(i); done.append(c); rec(done, rest); done.deleteCharAt(done.length()-1);http://blueocean-penn.blogspot.com/2015/11/permutation-sequence.html
The best way to approach the problem is to divide and conquer:
let's start with numbers 1, 2, 3, 4, and we can divide the sequences into 4 groups each starts with 1, 2, 3, 4, the number of sequences in each are 3!, k/3! will decide which group the kth sequence belongs to, saying k=9, k/3! = 1, so kth sequence belongs with group starts with 2.
now we have 1,3,4 and we should look for k%3!=9%6=3th sequence in this set
And we can use recursion to do divide and conquer work.
public static List<Integer> permutationByRank(int n, int k){
//prepare the set
List<Integer> list = new ArrayList<Integer>();
for(int i=1; i<=n; i++)
list.add(i);
//calculate the group size
int size = factor(n-1);
return permuByRankUtil(list, k-1, size);
}
/*
* here k starts at 0 to n!-1 for easy computing purpose
*/
public static List<Integer> permuByRankUtil(List<Integer> nums, int k, int f){
int size = nums.size();
//base case
if(size==1)
return nums;
else{
//decide group index
int index = k/f;
int first = nums.remove(index);
List<Integer> re = permuByRankUtil(nums, k%f, f/(size-1));
re.add(0, first);
return re;
}
}
http://www.zrzahid.com/k-th-permutation-sequence/
https://discuss.leetcode.com/topic/15592/java-solution-with-o-1-space-modified-from-the-solution-for-permutation-1
// k is 1-based
public String getPermutation(int n, int k) {
int[] nums = getNums(n);
permute(nums, k-1);
return convertArrayToString(nums);
}
// k is 0-based
public void permute(int[] nums, int k) {
int divisor = fact(nums.length-1);
for ( int i = 0; i <= nums.length-2; i++ ) {
int swapTime = k/divisor;
for ( int j = 1; j <= swapTime; j++ ) { swap(nums, i, i+j); }
k %= divisor; divisor /= nums.length-i-1;
}
}
// Helper Method
public int fact(int n) { return n <= 1 ? 1 : n*fact(n-1); }
public void swap(int[] arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; }
public String convertArrayToString(int[] arr){
StringBuffer s = new StringBuffer();
for ( int element : arr ) { s.append(element); }
return s.toString();
}
public int[] getNums(int n) {
int[] nums = new int[n];
for ( int i = 0; i < nums.length; i++ ) { nums[i] = i+1; }
return nums;
}
Read full article from LeetCode - Permutation Sequence | Darren's Blog