Idiot-maker

  :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

https://leetcode.com/problems/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.

解题思路:

开始把这题当成 Permutations ,直接dfs出所有组排列,然后去第k个,按照本题的意思,是一定会超时的,反正代码也写一下吧。

public class Solution {
    public String getPermutation(int n, int k) {
        List<String> permutationList = new ArrayList<String>();
        int[] visited = new int[n];
        dfs(permutationList, n, new StringBuffer(), 0, visited);
        return permutationList.get(k - 1);
    }

    public void dfs(List<String> permutationList, int n, StringBuffer current, int step, int[] visited){
        if(current.length() ==  n){
            permutationList.add(current.toString());
            return;
        }

        for(int i = 0; i < n; i++){
            if(visited[i] == 1){
                continue;
            }
            current.append(i + 1);
            visited[i] = 1;
            dfs(permutationList, n, current, step + 1, visited);
            current.deleteCharAt(current.length() - 1);
            visited[i] = 0;
        }
    }
}

然后再一想,对于上面的例子,比如k=5,那么前4次完全可以不算,因为第一位肯定是3了。为什么?因为以每个数字开头的组合,都一定有(n-1)!个。所以我们只要看这第k个数字在第m组的第n个就可以了。

这里m=(k - 1) / (n - 1)! + 1,n=(k-1) % (n - 1)! + 1。所以要求的第k个数字,一定是mxxxxxx的形式,而且在这xxxxxx的组合中,是第n个。

代码写出来,仍然超时。

public class Solution {
    public String getPermutation(int n, int k) {
        List<String> permutationList = new ArrayList<String>();
        int[] visited = new int[n];
        int factorial = fac(n - 1);
        int base = (k - 1) / factorial;
        int kth = (k - 1) % factorial + 1;
        
        visited[base] = 1;
        
        dfs(permutationList, n, new StringBuffer(String.valueOf(base + 1)), kth, visited, base);
        
        return permutationList.get(kth - 1);
    }

    public void dfs(List<String> permutationList, int n, StringBuffer current, int kth, int[] visited, int base){
        if(current.length() ==  n){
            permutationList.add(current.toString());
            return;
        }
        
        if(permutationList.size() == kth){
            return;
        }

        for(int i = 0; i < n; i++){
            if(visited[i] == 1){
                continue;
            }
            current.append(i + 1);
            visited[i] = 1;
            dfs(permutationList, n, current, kth + 1, visited, base);
            current.deleteCharAt(current.length() - 1);
            visited[i] = 0;
        }
    }
    
    public int fac(int n){
        int result = 1;
        for(int i = 1; i <= n; i++){
            result *= i;
        }
        return result;
    }
}

这时才想到,上面的思路不正是一个递归思路吗?或者迭代,这里都比较简单。我们对于第一位数字可以如此确定,后面所有位的数字也都可以这么确定了。

不能忘记的是,还是要有个去重的问题,当前第k个数字往前,如果已经选择过x个了,那么当前数字就是k+x。

public class Solution {
    public String getPermutation(int n, int k) {
        int[] visited = new int[n];
        return generate(n, k, visited);
    }
    
    public String generate(int n, int k, int[] visited){
        if(n == 0){
            return "";
        }
        int factorial = fac(n - 1);
        int base = (k - 1) / factorial;
        int kth = (k - 1) % factorial + 1;
        //除去前面已经选择过的数字
        int temp = 0;
        for(int i = 0 ; i < visited.length; i++){
            if(visited[i] == 1){
                base++;
            }
            if(i == base){
                break;
            }
        }
        visited[base] = 1;
        return String.valueOf(base + 1) + generate(n - 1, kth, visited);
    }
    
    public int fac(int n){
        int result = 1;
        for(int i = 1; i <= n; i++){
            result *= i;
        }
        return result;
    }
}

update 2015/06/04:

二刷,写了个迭代的。

public class Solution {
    public String getPermutation(int n, int k) {
        String res = "";
        int[] visited = new int[n + 1];
        for(int i = 0; i < n; i++) {    //从左往右迭代到第i位
            int bucketSize = fac(n - 1 - i);    //第i位的桶大小
            int digit = (k - 1) / bucketSize + 1;   //应该在第几个桶,这一位就是digit,但是要去掉已经选中的数字
            k = k - bucketSize * (digit - 1);   //方法1,剩下里面在第k个
            k = (k - 1) % bucketSize + 1;   //方法2,剩下里面在第k个
            for(int j = 1; j <= digit; j++){
                if(visited[j] == 1){
                    digit++;
                }
            }
            visited[digit] = 1;
            res = res + String.valueOf(digit);
        }
        return res;
    }
    
    public int fac(int n) {
        int res = 1;
        for(int i = 1; i <= n; i++) {
            res *= i;
        }
        return res;
    }
}

 //20180919

class Solution {
    public String getPermutation(int n, int k) {
        StringBuffer sb = new StringBuffer();
        int[] visited = new int[n];
        dfs(n, k, visited, sb);
        return new String(sb);
    }
    
    public void dfs(int n, int k, int[] visited, StringBuffer sb) {
        if (n <= 0) {
            return;
        }
        int factorial = fact(n - 1);
        int here = (k - 1) / factorial + 1;
        int left = k - factorial * (here - 1);
        for (int i = 0; i < here; i++) {
            if (visited[i] == 1) {
                here++;
            }
        }
        visited[here - 1] = 1;
        sb.append(here);
        dfs(n - 1, left, visited, sb);
    }
    
    public int fact(int n) {
        int result = 1;
        while (n > 0) {
            result *= n;
            n--;
        }
        return result;
    }
}

 

posted on 2015-03-24 16:17  NickyYe  阅读(229)  评论(0)    收藏  举报