LeetCode - 46. Permutations

本文介绍两种生成全排列的方法:一种是通过不断填充元素至现有列表的空隙;另一种是利用字典序法寻找下一个排列。文章详细展示了每种方法的实现步骤及核心代码。

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

第一种方法的思想是不断地向原来list的空隙中添加新的元素,比如对于[1,2,3],首先我们将要返回的结果初始化为[[1]],接下来向结果中的所有list的空隙添加2,也就是[[2,1], [1,2]],最后一步继续向结果中所有的list的空隙中添加3,代码如下:

public class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        
        // Corner case
        if(nums == null || nums.length == 0){
            return result;
        }        
    
        // Init
        List<Integer> l0 = new ArrayList<Integer>();
        l0.add(nums[0]);
        result.add(l0);
        
        for(int i = 1; i < nums.length; i++){
            List<List<Integer>> temp_result = new ArrayList<List<Integer>>();       // temp result
            
            // Add new item to current lists
            for(int j = 0; j <= i; j++){
                for(List<Integer> l : result){
                    List<Integer> temp_list = new ArrayList<Integer>(l);
                    temp_list.add(j, nums[i]);
                    temp_result.add(temp_list);
                }
            }
            result = temp_result;
        }
        
        return result;
    }
}


第二种方法是字典序法,字典序法是用于寻找当前排列的下一个字典序排列的算法,如下图所示:

形式化的表示方法就是:

对于使用字典序法求全排列的情况,我们首先需要对给定的数组进行从小到大的排序,将初始list添加到结果中,然后在factorial(nums.length)个循环中,逐步找到next permutation并添加到结果中,代码如下:

public class Solution{
    public int factorial(int n){
        return (n == 1 || n == 0) ? 1 : factorial(n - 1) * n;
    }

    public void reverse(List<Integer> list, int begin, int end){
        for(int i = begin, j = end; i < j; i++){
            list.add(i, list.remove(j));
        }
    }
    
    // Use lexicographical order method to find next permutation
    public List<Integer> nextPermutation(List<Integer> nums){
        // Find last ascending order
        int i = nums.size() - 1;
        while(i > 0 && nums.get(i - 1) >= nums.get(i)){
            i--;
        }

        // Find last number larger than nums[i - 1]
        int j = i;
        while(j < nums.size() && nums.get(j) > nums.get(i - 1)){
            j++;
        }

        // Swap nums[i - 1] and nums[j - 1]
        int temp = nums.get(i - 1);
        nums.set(i - 1, nums.get(j - 1));
        nums.set(j - 1, temp);

        // Reverse numbers after i
        reverse(nums, i, nums.size() - 1);

        List<Integer> result = new ArrayList<Integer>();
        result.addAll(nums);
        return result;
    } 

    public List<List<Integer>> permute(int[] nums){
        List<List<Integer>> result = new ArrayList<List<Integer>>();

        // Corner case
        if(nums == null || nums.length == 0){
            return result;
        }

        int length = nums.length;
        Arrays.sort(nums);      // lexicographical order requires ascending order sort

        // Convert array to list
        List<Integer> list0 = new ArrayList<Integer>();
        for(int i = 0; i < length; i++){
            list0.add(nums[i]);
        }

        List<Integer> l1 = new ArrayList<Integer>();
        l1.addAll(list0);
        result.add(l1);

        // Find next permutation
        for(int i = 1; i < factorial(length); i++){
            result.add(nextPermutation(list0));
        }
        return result;
    }
}


知识点:

1. ArrayList的初始化方式new ArrayList<Integer>(n) / new ArrayList<Integer>(another ArrayList)

2. factorial(n)的写法

3. 在一个List中,reverse(List<Integer> list, int begin, int end)的写法

4. 寻找下一个字典序排列的字典序法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值