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):
"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.
【问题描述】
给定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 }