leetcode 60 第k个排列
题目:
求按字典序生成的第k个排列。
思路一:
先生成所有全排列,然后按字典序排序,取第k个即可。事实证明完全不行,超时。
思路二:
康托展开的逆运算。关于康托展开的有关内容,参考这位兄弟的博客。(n年前本科的时候似乎上课讲过。。。)思路还是比较简单的,如果比较熟悉的话。
1 class Solution { 2 3 //这题需要用到康托展开的逆运算来高效解决 4 public String getPermutation(int n, int k) { 5 6 //计算1!, 2!, ..., (n - 1)! 7 int[] factorial = new int[n]; 8 factorial[0] = 1; 9 for (int i = 1; i < n; i++) { 10 factorial[i] = factorial[i - 1] * i; 11 } 12 13 boolean[] isVisit = new boolean[n + 1]; //表示是否数字1~n是否被访问(是否加入了排列) 14 int tmp = k - 1; //说明之前有k - 1个排列 15 int res = 0; 16 StringBuilder sb = new StringBuilder(); 17 18 //进行n - 1次迭代 19 for (int i = n - 1; i >= 1; i--) { 20 res = tmp / factorial[i]; //说明有res个数字(不算已经加入排列的数字)是小于这位的数字的 21 tmp = tmp % factorial[i]; //更新下一次的tmp 22 23 //找出未被访问的第res + 1个数字,并加入排列 24 int j, cnt; 25 for (j = 1, cnt = 0; j <= n && cnt <= res; j++) { 26 if (!isVisit[j]) { 27 cnt++; 28 } 29 } 30 j--; 31 sb.append(j); 32 isVisit[j] = true; 33 } 34 35 //最后一个数字就是剩下的未被访问的那个数字 36 for (int i = 1; i <= n; i++) { 37 if (!isVisit[i]) { 38 sb.append(i); 39 break; 40 } 41 } 42 return sb.toString(); 43 } 44 }