LeetCode 46. Permutations 全排序(Java)

题目:

Given a collection of distinct integers, return all possible permutations.

Example:
Input: [1,2,3]
Output:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]

解答:

解法一:回溯法

看到题目后立马会想到,这是一种典型的回溯思想,在之前的 LeetCode 17/22/29/30 题中,我们已经多次采用过回溯思想进行解答,此题采用的思路基本一致,回溯+递归。
注意:

  1. 对 nums 进行遍历时,要进行去重处理,即用 list.contains()进行重复判断,如果 list 中出现过相同数字,就直接 continue
  2. 回溯结束后,通过 list.remove(list.size()-1);,去除 list 中最后一个元素,从而进行下一次循环
class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> list = new ArrayList<>();
        recursion(res, list, nums);
        return res;
    }
    private void recursion(List<List<Integer>> res, List<Integer> list, int[] nums) {
        if(list.size() == nums.length) {
            res.add(new ArrayList<>(list));
            return;
        }
        for(int i=0; i<nums.length; i++) {
            if(list.contains(nums[i])) {
                continue;
            }
            list.add(nums[i]);
            recursion(res, list, nums);
            list.remove(list.size()-1);
        }
    }
}

但提交结果显示效率并不算高,不是时间更优的解法。
在这里插入图片描述

解法二:字典排序

参看他人的解法,采用了字典排序的思想

在 LeetCode 31 题中,我们第一次接触了字典序算法,回顾:LeetCode 31. Next Permutation 下一个排列(字典序算法)
在31 题中,我们是根据字典序列的特点,寻找某一字典序列的下一个序列。这道题同理,先对nums进行排序,然后不断地寻找下一个排序,用 nextPermutation() 判断是否存在下一个排序,添加排序好的 list 时,采用do-while 循环能使得第一个排序好的数组先加入 res 中。(do-while 循环先执行循环体,后判断 while(true) 则进行下一次循环)

class Solution {
    public List<List<Integer>> permute(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> res = new ArrayList<>();
        do {
            List<Integer> list = new ArrayList<>();
            for (int num : nums) {
                list.add(num);
            }
            res.add(list);
        } while (nextPermutation(nums));
        return res;
    }
    //判断是否有下一个排序,若没有则 return false
    public boolean nextPermutation(int[] nums) {
        if (nums.length == 1) {
            return false;
        }
        int p = -1;
        for (int i = nums.length - 2; i >= 0; i--) {
            if (nums[i] < nums[i + 1]) {
                p = i;
                break;
            }
        } 
        if (p != -1) {
            int temp = nums[p];
            int q = nums.length - 1;
            while (nums[q] <= temp) {
                q--;
            } 
            nums[p] = nums[q];
            nums[q] = temp; 
            reverse(p + 1, nums);
        } else {
            return false;
        } 
        return true;
    }
  
    public void reverse(int k, int[] nums) {
        if (k >= nums.length) return;
        int i = k;
        int j = nums.length - 1;
        while (i < j) {
            int list = nums[i];
            nums[i] = nums[j];
            nums[j] = list;
            i++;
            j--;
        }
    }
}

在这里插入图片描述

解法三:递归

思路:以每个数开始的全排列,把每个数换到最前面一次,找到它后面数的所有全排列,把前面的数加上,作为一个 list,再把换到前面的数换回去,接着换下一个数

class Solution {
    List<List<Integer>> result = new ArrayList<List<Integer>>();
    public List<List<Integer>> permute(int[] nums) {
 
        perm(nums, 0, nums.length-1);
        return result;
    }
    public void perm(int[] nums, int start, int end){
        if (start == end){
            List<Integer> list = new ArrayList<>();
            for (int i = 0; i < nums.length; i++){
               list.add(nums[i]); 
            }
            this.result.add(list);
        }else{
            for (int i = start; i <= end; i++){
                swap(nums,start, i);
                perm(nums,start+1, end);
                swap(nums, start, i);
            }
        }     
    }
    public void swap(int[] nums,int p, int q){
        int temp = nums[p];
        nums[p] = nums[q];
        nums[q] = temp;
    }
}

在这里插入图片描述

你可能感兴趣的:(LeetCode)