leetcode 60. 排列序列

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

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

"123"
"132"
"213"
"231"
"312"
"321"
给定 n 和 k,返回第 k 个排列。

 

示例 1:

输入:n = 3, k = 3
输出:"213"
示例 2:

输入:n = 4, k = 9
输出:"2314"
示例 3:

输入:n = 3, k = 1
输出:"123"
 

提示:

1 <= n <= 9
1 <= k <= n!

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/permutation-sequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

大多数的解法是回溯,从小到大统计每个数字。

其实排序之后是有规律的,可以不用回溯,直接归纳每个数字出现的位置,直接拼接字符串。

    public String getPermutation(int n, int k) {
        // 先把集中特殊的情况直接返回
        if (n == 1) {
            return "1";
        }
        if (n == 2) {
            if (k == 1) {
                return "12";
            }
            return "21";
        }
        StringBuilder sb = new StringBuilder(n);
        if (k == 1) {
            for (int i = 0; i < n; i++) {
                sb.append(i + 1);
            }
            return sb.toString();
        }

        // 开始一般的形式
        
        int a = 1;
        int limit = 0;

        for (int i = 2; i <= n; i++) {
            a *= i;
            limit = i;
            if (a > k) {
                break;
            }
        }
        int[] arr = new int[n];
        Arrays.fill(arr, -1);
        int d = 0;
        for (int i = n - limit; i > 0; i--) {
            arr[d++] = 1;
        }
        a /= limit;

        int p;
        int z = d;
        while (k != 0) {
            p = k / a;
            k = k % a;
            if (k != 0) {
                p++;
            } else {
                if (z + 1 < n) {
                    arr[z + 1] = 0;
                }
            }
            a /= (--limit);
            if (z + 1 < n) {
                arr[z++] = p;
            }
        }
        int[] arr2 = new int[n];
        for (int i = 0; i < n; i++) {
            arr2[i] = i + 1;
        }

        for (int i = 0; i < n; i++) {
            int index = arr[i];
            if (index == 0) {
                for (int j = n - 1; j >= 0; j--) {
                    if (arr2[j] != 0 && arr2[j] != -1) {
                        sb.append(arr2[j]);
                    }
                }
                break;
            }
            if (index == -1) {
                for (int j = 0; j < n; j++) {
                    if (arr2[j] != 0 && arr2[j] != -1) {
                        sb.append(arr2[j]);
                    }
                }
                break;
            }
            int value = get(arr2, index, n);
            sb.append(value);
        }
        return sb.toString();
    }

    /**
     * 获取数组中的值
     * @param arr
     * @param index
     * @param n
     * @return
     */
    private static int get(int[] arr, int index, int n) {
        int num = 1;
        for (int j = 0; j < n; j++) {
            int i = arr[j];
            if (i != 0 && i != -1) {
                if (index == num) {
                    arr[j] = -1;
                    return i;
                }
                num++;
            } else if (i == 0) {
                return i;
            }
        }
        return -1;
    }

写法比较复杂,但是时间上可以100%.

posted @ 2021-04-15 16:05  旺仔古李  阅读(99)  评论(0编辑  收藏  举报