全排列(力扣第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