【题目描述】
给出集合 [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解题之前,一定不要看题解,看了就“破功”了!