题目描述

给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。

按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:

示例:

输入: 3
输出:
1."123"
2."132"
3."213"
4."231"
5."312"
6."321"

思路

1.最简单方法就是按照46.全排列计算出所有的情况,然后选取第K个元素,但是运行超时了。
2.我们可以进一步思考,既然是递归实现的,我们便可以对递归树进行剪枝,从而缩短其执行时间。
3.我们可以发现,假如有n个元素,我们选定了第一个元素,其可能产生的排列组合是(n-1)!个,所以我们可以根据阶乘和k的大小比较进行剪枝操作,若阶乘<k,便进行剪枝。

Java代码实现

   public String getPermutation(int n, int k) {
        List<Integer> nums = new ArrayList<>();
        for (int i = 1; i <= n; i++) {
            nums.add(i);
        }
        boolean[] flags = new boolean[n];
        return backTraceNumStr(new StringBuffer(),nums,k,n,0,flags);
    }

    private String backTraceNumStr(StringBuffer res, List<Integer> nums, int k,int n,int depth,boolean[] flags){
        if(depth == n){
            return res.toString();
        }

        //该分支最多的组合数
        int branchNum = factorial(n-1-depth);

        for (int i =0; i < n; i++) {
            if(flags[i]){
                continue;
            }
            if(branchNum < k){
                k -= branchNum;
                continue;
            }
            res.append(nums.get(i));
            flags[i] = true;
            return backTraceNumStr(res,nums,k,n,depth+1,flags);
        }

        return null;
    }

    private int factorial(int n){
        int res = 1;
        for (int i = n; i > 0; i--) {
            res *= i;
        }
        return res;
    }

Golang代码实现

func getPermutation(n int, k int) string {
    nums := make([]int,0)
    flags := make([]bool,n)
    for i:=1; i<=n; i++ {
        nums = append(nums, i)
    }

    return getPermutationBackTrace(nums,flags,"",n,k,0)
}

func getPermutationBackTrace(nums []int,flags []bool,cur string,n int,k int,depth int) string{
    if len(cur) == n{
        return cur
    }
    curMax := compute(n-depth-1)

    for i:=0; i<len(nums);i++{
        if flags[i]{
            continue
        }
        if curMax<k {
            k -= curMax
            continue
        }
        flags[i] = true
        return getPermutationBackTrace(nums,flags,cur+strconv.Itoa(nums[i]),n,k,depth+1)
    }
    return ""
}

func compute(n int) int {
    res := 1
    for i:=n; i>0; i-- {
        res *= i
    }
    return res
}