【题目描述】
给出集合 [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)1 <= n <= 9
2)1 <= k <= n!
【题目链接】. - 力扣(LeetCode)
【解题代码】
package number;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
public class GetPermutation {
public static void main(String[] args) {
//int n = 4, k = 9;
int n = 4, k = 3;
System.out.println("计算结果:" + new GetPermutation().getPermutation(n, k));
}
public String getPermutation(int n, int k) {
// 生成1到n的数组
int[] nums = IntStream.range(1, n + 1).toArray();
// 运行K次获取下一个数字排列组合
for (int i = 0; i < k - 1; i++) {
nextPermutation(nums);
}
// 最后将生成的整数数组结果转换成字符串
return Arrays.stream(nums).mapToObj(String::valueOf).reduce((a, b) -> a + b).get();
}
private void nextPermutation(int[] nums) {
// 从倒数第二个数开始,尝试能够递增替换此数字,依次向前推进
int i = nums.length - 2;
Lable:
for (; i >= 0; i--) {
// 往后找比当前数大的数,将两个数交换,然后跳出整个循环
for (int j = nums.length - 1; j > i; j--) {
if (nums[i] < nums[j]) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
break Lable;
}
}
}
// 后面的数字,从小到大排序即可
Arrays.sort(nums, i + 1, nums.length);
}
}
【解题思路】
之前此题已经在博文LeetCode-60题:排列序列解法一(原创)-CSDN博客中介绍了一种解法,虽然提交成功,但运行时长400多毫秒,而且递归实现有些晦涩,还有没有其它更加巧妙的方法呢,本人苦苦思索,拿着数字排列“3124,3142,3214,3241,3412。。。“翻来覆去的去找其中的规律,突然间真是灵光一闪,发现如下真理:每个数字排列的下一个排列:就是从倒数第二个数字开始,往后找到比此数大的数字,两者进行交换,然后再将后面的数字进行排序即可,找不到的话向前推进。。。发现这么大的天机,当下真是兴奋不已,立马修改好代码,运行提交LeetCode成功!
【解题步骤】
- 定义一个递归回溯函数,获取输入的数字集合下一个排列
private void nextPermutation(int[] nums) {。。。}
- 主函数里,先初始化数字集合为最小排列序列,然后对此数字集合取k-1次下一个排列,然后返回结果即可
// 生成1到n的数组 int[] nums = IntStream.range(1, n + 1).toArray(); // 运行K次获取下一个数字排列组合 for (int i = 0; i < k - 1; i++) { nextPermutation(nums); } // 最后将生成的整数数组结果转换成字符串 return Arrays.stream(nums).mapToObj(String::valueOf).reduce((a, b) -> a + b).get();
- nextPermutation函数里i从倒数第二个数开始,尝试能够递增替换此数字,依次向前推进,往后找比当前数大的数,将两个数交换,然后跳出整个循环
// 已经访问到数字集合尾部,当前排列完成生成, 序列号加1并返回 if (n == nums.length) { return m + 1; }
- 然后将后面的数字,从小到大排序即可
Arrays.sort(nums, i + 1, nums.length);
【思考总结】
- 算法实现精要:每个数字排列的下一个排列:就是从倒数第二个数字开始,往后找到比此数大的数字,两者进行交换,然后再将后面的数字进行排序即可,找不到的话向前推进。。。;
- 算法实现最好能精益求精,不可浅尝辄止,温故而知新比做新的算法题可能收获更大;
- 一定要有自己的原创算法思想,不能一味按照公式去套,那样的话就只是机械的应试刷题,没有自己的灵魂!没有自己的思想!
- LeetCode解题之前,一定不要看题解,看了就“破功”了!