LeetCode-60题:排列序列解法二(原创)

本文介绍了如何优化LeetCode第60题的排列序列解法,通过观察排列规律,发现从倒数第二个数开始找到较大数交换并排序,简化了递归实现,提高了运行效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【题目描述】

      给出集合 [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题:排列序列解法一(原创)-优快云博客中介绍了一种解法,虽然提交成功,但运行时长400多毫秒,而且递归实现有些晦涩,还有没有其它更加巧妙的方法呢,本人苦苦思索,拿着数字排列“3124,3142,3214,3241,3412。。。“翻来覆去的去找其中的规律,突然间真是灵光一闪,发现如下真理:每个数字排列的下一个排列:就是从倒数第二个数字开始,往后找到比此数大的数字,两者进行交换,然后再将后面的数字进行排序即可,找不到的话向前推进。。。发现这么大的天机,当下真是兴奋不已,立马修改好代码,运行提交LeetCode成功!

【解题步骤】

  1. 定义一个递归回溯函数,获取输入的数字集合下一个排列
    private void nextPermutation(int[] nums) {。。。}
  2. 主函数里,先初始化数字集合为最小排列序列,然后对此数字集合取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();
  3. nextPermutation函数里i从倒数第二个数开始,尝试能够递增替换此数字,依次向前推进,往后找比当前数大的数,将两个数交换,然后跳出整个循环
    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;
    	    }
    	}
    }
  4. 然后将后面的数字,从小到大排序即可
    Arrays.sort(nums, i + 1, nums.length);

【思考总结】

  1. 算法实现精要:每个数字排列的下一个排列:就是从倒数第二个数字开始,往后找到比此数大的数字,两者进行交换,然后再将后面的数字进行排序即可,找不到的话向前推进。。。;
  2. 算法实现最好能精益求精,不可浅尝辄止,温故而知新比做新的算法题可能收获更大;
  3. 一定要有自己的原创算法思想,不能一味按照公式去套,那样的话就只是机械的应试刷题,没有自己的灵魂!没有自己的思想!
  4. LeetCode解题之前,一定不要看题解,看了就“破功”了!      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值