个人记录-LeetCode 46. Permutations

来源:互联网 发布:python unpack修饰符 编辑:程序博客网 时间:2024/06/15 16:07

问题:
Given a collection of distinct numbers, return all possible permutations.

For example,
[1,2,3] have the following permutations:

[  [1,2,3],  [1,3,2],  [2,1,3],  [2,3,1],  [3,1,2],  [3,2,1]]

问题要求:得到指定数组的全排列。

代码示例:
1、暴力递归
回忆一下我们通常求全排列的方法。
例如有3个数,它们全排列的大小为:
第1个位置,可以为3个数中的任意一个,共有3种选择;
第2位置,在选完第1个位置的数后,可以为剩下2个数中的任意一个,共有2种选择;
第3个位置,在选完第1个和第2个位置的数后,只有1种选择。
因此,整体共有6种选择。

我们也可以按照这种思路写代码:

public class Solution {    public List<List<Integer>> permute(int[] nums) {        List<List<Integer>> result = new ArrayList<>();        if (nums == null || nums.length < 1) {            return result;        }        //现将数组排序,这样相同的数字排在一起,可以跳过,避免重复结果        Arrays.sort(nums);        //flag记录一个数字是否被选择过        boolean[] flag = new boolean[nums.length];        //path记录每次排列的结果        List<Integer> path = new ArrayList<>();        //无脑暴力递归        permute(nums, path, flag, result);        return result;    }    private void permute(int[] nums, List<Integer> path, boolean[] flag, List<List<Integer>> result) {        //已经完成了所有位置的选择,返回结果        if (path.size() == nums.length) {            result.add(path);            return;        }        boolean first = true;        //prev记录当前位置,上一次选择的数        int prev = -1;        for (int i = 0; i < nums.length; ++i) {            if (!flag[i]) {                if (first) {                    prev = nums[i];                    first = false;                } else {                    //避免在同一个位置,选择相同的数,避免重复                    if (nums[i] == prev) {                        continue;                    }                    prev = nums[i];                }                //生成新的位图                List<Integer> tempList = new ArrayList<>(path);                boolean[] tempFlag = new boolean[nums.length];                System.arraycopy(flag, 0, tempFlag, 0, nums.length);                //添加本次信息                tempFlag[i] = true;                tempList.add(nums[i]);                //继续递归                permute(nums, tempList, tempFlag, result);            }        }    }}

2、改进
前一种方法选择每个位置的数时,需要判断其它数是否已经被选择过,比较耗费时间。这种过程我们称为“为位置选数”。

下面这个过程,可以称为“为数选位置”。
第1个数与后续每个数交换位置,得到新数组后,在新数组的基础上递归。
此时,第1个数分别放到了0~n-1的位置上。

然后,开始为第2个数选位置。
由于第1个数和第2个数交换过,因此已经有一个递归序列,处理第2个数放到第1个位置的情况了。
为了避免重复,将第2个数与其后的每个数交换位置,得到下一个新数组,然后继续在此基础上递归。
此时,第2个数分别放在了1~n-1的位置上。

以此类推,得到最终结果。
不过这种方式会有重复的结果。

public class Solution {    public List<List<Integer>> permute(int[] nums) {        List<List<Integer>> result = new ArrayList<>();        //仍然排序,避免重复        Arrays.sort(nums);        //迭代        perm(result,nums,0,nums.length-1);        return result;    }    public static void perm(List<List<Integer>> result, int[] nums, int start, int end) {        //start记录此次交换的起始位置        if(start == end){            Integer[] tempNums = new Integer[nums.length];            for (int i = 0; i < nums.length; ++i) {                tempNums[i] = nums[i];            }            result.add(Arrays.asList(tempNums));        } else {            boolean flag = true;            int prev = -1;            for(int i=start; i<=end; i++){                //以下这一段仍是避免重复                if (flag) {                    prev = nums[i];                    flag = false;                } else {                    //prev与nums[i]的比较,与1方法类似,避免重复交换                    //nums[start]与nums[i]比较,避免某个位置与起始位置一致                    if (prev == nums[i] || nums[start] == nums[i]) {                        continue;                    } else {                        prev = nums[i];                    }                }                //交换当前起始位置和后续位置的数                int temp = nums[start];                nums[start] = nums[i];                nums[i] = temp;                //继续迭代                perm(result, nums,start+1,end);                //还原数组                temp = nums[start];                nums[start] = nums[i];                nums[i] = temp;            }        }    }}
0 0
原创粉丝点击