当前位置: 面试刷题>> 第k个排列 (经典算法题500道)


题目描述

给定一个包含从1到n的所有整数的数组,和一个整数k,返回这个数组中第k个排列。

排列从序列的字典序排列开始定义。例如,给定数组 [1,2,3],其排列为:

"123"
"132"
"213"
"231"
"312"
"321"

对于n = 3 和 k = 4,则第4个排列为 "231"

解题思路

我们可以使用回溯法(或称为深度优先搜索)来解决这个问题,但更高效的方法是使用数学方法来定位第k个排列。基本思路是:

  1. 从最高位(即数组的开头)开始,通过计算当前位上可以放置的数字的个数(未使用的数字),来确定当前位的数字。
  2. 确定当前位数字后,计算其前面所有小于它的数字的个数,这决定了当前数字是第几个排列的起始部分。
  3. 递归地处理剩余的数组和剩余的k值。

PHP 示例代码

function getPermutation($n, $k) {
    $nums = range(1, $n);
    $factorial = array_fill(0, $n, 0);
    $factorial[0] = 1;
    for ($i = 1; $i < $n; $i++) {
        $factorial[$i] = $factorial[$i - 1] * $i;
    }

    $k--; // 转换为从0开始的索引
    $result = '';
    while ($n > 0) {
        $groups = $factorial[$n - 1];
        $digit = intdiv($k, $groups) + 1;
        $k = $k % $groups;

        // 找出当前位的数字,并将其从数组中移除
        $result .= array_splice($nums, $digit - 1, 1)[0];
        $n--;
    }

    return strrev($result); // 因为是从高位到低位构建的,所以需要反转字符串
}

// 示例
echo getPermutation(3, 4); // 输出: 231

Python 示例代码

def getPermutation(n, k):
    nums = list(range(1, n + 1))
    factorial = [1] * n
    for i in range(1, n):
        factorial[i] = factorial[i - 1] * i

    k -= 1
    result = []
    while n > 0:
        groups = factorial[n - 1]
        digit = (k // groups) + 1
        k %= groups
        
        result.append(str(nums.pop(digit - 1)))
        n -= 1

    return ''.join(result)

# 示例
print(getPermutation(3, 4))  # 输出: 231

JavaScript 示例代码

function getPermutation(n, k) {
    const nums = Array.from({ length: n }, (_, i) => i + 1);
    const factorial = Array(n).fill(1).map((_, i) => i ? factorial[i - 1] * i : 1);

    k--; // 转换为从0开始的索引
    let result = '';
    while (n > 0) {
        const groups = factorial[n - 1];
        const digit = Math.floor(k / groups) + 1;
        k %= groups;

        // 找出当前位的数字,并将其从数组中移除
        result += nums.splice(digit - 1, 1)[0];
        n--;
    }

    return result;
}

// 示例
console.log(getPermutation(3, 4)); // 输出: 231

码小课网站中有更多相关内容分享给大家学习,欢迎访问码小课网站深入学习更多编程知识和算法技巧。

推荐面试题