全排列(力扣第46题)

题目:给定一个 没有重复数字的序列,返回其所有可能的全排列。

示例:

输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]

分析:

  求给定一组数的全排列,也就是排列组合问题,所以属于Backtracking(回溯)问题,通过DFS解决,只不过需要注意的是,我们一般使用DFS的时候都会设置一个访问标记的数组,用于保证深度递归的过程中,某一个元素不会被重复访问,但是由于现在我们要求的是排列组合问题,所以我们要尽可能的把所有的解求出来,那么只要一条递归路径中有一个元素不同,那就是不用的递归路径,所以当我们从一个元素递归返回的时候,要将此元素对应于访问标记数组中的值复位,保证从其他路径路过此元素时,能够正常的访问。

  其实对于一组数来说,假设一共有n个数,那么这n个数全排列的结果是n!个,其具体的计算结果是 n * (n-1) * ……* 2 * 1 。我们可以将这个计算过程想象成我们使用DFS搜索时进行搜索的过程,比如最开始的时候,我们从哪个元素最先开始搜索,此时一共有n个数未被访问,那么就有n种选择;然后继续搜索,那么还剩n-1个数未被访问,此时可选择走的方向就有n-1个选择;……,以此类推,就是求所有的排列的过程。每到一个元素,进行的下一步走向的选择,就是通过for循环实现,保证所有的可能都要经历。

代码实现:

    private List<List<Integer>> reslist;

    public List<List<Integer>> permute(int[] nums) {


        if (nums.length == 0 || nums == null){
            return new ArrayList<>();
        }
        int n = nums.length;
        boolean[] isVisited = new boolean[n];
        reslist = new ArrayList<List<Integer>>();
        List<Integer> sortres = new ArrayList<>();
        for (int i = 0; i < nums.length; i++) {

            findAllSort(nums,i,isVisited,sortres);
        }
        return reslist;
    }

    private void findAllSort(int[] nums, int i, boolean[] isVisited, List<Integer> sortres) {

        if (isVisited[i]){
            return;
        }

        isVisited[i] = true;
        sortres.add(nums[i]);

        if (sortres.size() == nums.length){
            reslist.add(new ArrayList<>(sortres));
            isVisited[i] = false;
            sortres.remove(sortres.size()-1);
            return;
        }

        for (int i1 = 0; i1 < isVisited.length; i1++) {

            if (!isVisited[i1]){
                findAllSort(nums,i1,isVisited,sortres);
            }
        }

        isVisited[i] = false;
        sortres.remove(sortres.size()-1);
    }

记住,当遍历完一条路径的时候,给此路径添加到结果列表,需要新建一个list对象,然后将sortres结果传进去,直接将sortres添加到结果列表中是不行的,因为当我们再一次修改sortlist时,原先存于结果列表的内容也会被修改。

上面是我自己实现的代码,然后也参考了cyc2018的代码,他的代码比我的性能要好一些,但是我俩的做法思想基本是一样的:

public List<List<Integer>> permute(int[] nums) {
    List<List<Integer>> permutes = new ArrayList<>();
    List<Integer> permuteList = new ArrayList<>();
    boolean[] hasVisited = new boolean[nums.length];
    backtracking(permuteList, permutes, hasVisited, nums);
    return permutes;
}

private void backtracking(List<Integer> permuteList, List<List<Integer>> permutes, boolean[] visited, final int[] nums) {
    if (permuteList.size() == nums.length) {
        permutes.add(new ArrayList<>(permuteList)); // 重新构造一个 List
        return;
    }
    for (int i = 0; i < visited.length; i++) {
        if (visited[i]) {
            continue;
        }
        visited[i] = true;
        permuteList.add(nums[i]);
        backtracking(permuteList, permutes, visited, nums);
        permuteList.remove(permuteList.size() - 1);
        visited[i] = false;
    }
}

参考:cyc2018

posted @ 2020-07-05 21:33  有心有梦  阅读(178)  评论(0编辑  收藏  举报