LeetCode 60. Permutation Sequence

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):

  1. "123"
  2. "132"
  3. "213"
  4. "231"
  5. "312"
  6. "321"

Given n and k, return the kth permutation sequence.

Note: Given n will be between 1 and 9 inclusive.


【问题描述】

给定1到n这n个数字,他们的排列组合共有n!个, 把这些数字排列组合的得到的数升序排序,返回其中第k个。


【思路】

我们先看上面的例子,对于[1,2,3],如下是他们的组合:

这些组合数按照大小排序以后我们发现他们分别以1/2/3开头,而且以这些数字开头的排列数目是一样的。在以1开头的排列中,如果不看最高位,那么剩下的部分以2/3开头。而且以它们开头的排列数的数目也是一样的。发现了这个规律以后我们可以做这样的事情:

首先维持一个列表<1,2,...,n>,列表中的元素升序排列。

给定一个n和k,我们能计算出总的排列数是n!个,那么k是以第几个数开头的呢?这个数字是(k-1) / (n-1)! + 1,为什么k要减去1呢?比如k=2,那么k/2 + 1= 2,这样会导致如果k能被(n-1)!整除的话,计算出的开始数字增加1,而k减去1的话则会计算出正确的开头数字。

计算出开始数字是第m个数以后,我们要计算在以第m个数开头的数字中,我们要找第几个数,那么跟新k = (k-1) % (n-1)! + 1。这里的k减去1也是为防止k整除(n-1)!阶乘的时候,k % (n-1)!变为0,而此时k应该等于(n-1)!。

找到开始数字以后,我们从原始的数字序列中把m删除,继续上面的查找过程。直到列表中所有元素被取出。

举个例子:n = 3, k = 4:

1. 列表中元素<1,2,3>

2. 找到开始数字:m=(k-1) / (n-1)! + 1 = 2. 则以第二元素为开始数字,第二个元素是2.

3. 在以第二个元素开始的排列中我们找第 k = (k-1) % (n-1)! + 1 = 2个.

4. 删除第二个元素,列表变为<1,3>,n=2,k=2.

5. m = 2,列表中第二个元素是3.

6. k = 1.

7. 列表变为<1>,n=1,k=1.

8. 最后一个数字为1.

9. 返回结果231.

怎么样?这个过程懂了吗?


【java代码】

 1 public class Solution {
 2     public String getPermutation(int n, int k) {
 3         List<Integer> list = new LinkedList<Integer>();
 4         int totalnum = 1;
 5         StringBuilder sb = new StringBuilder();
 6         for (int i = 1; i <= n; i++) {
 7             list.add(i);
 8             totalnum *= i;
 9         }
10 
11         for (int i = n; i >= 1; i--) {
12             totalnum /= i;
13             int rank = (k-1) / totalnum;
14             k = (k-1) % totalnum + 1;
15             sb.append(list.get(rank));
16             list.remove(rank);
17         }
18 
19         return sb.toString();
20     }
21 }

原文地址:https://www.cnblogs.com/liujinhong/p/6007440.html