给定一个 没有重复 数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3] 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]其实像这种类型的题目有很多,因此dfs是一种必须要掌握的方法 DFS视频讲解
深度优先搜索
class Solution { public List<List<Integer>> permute(int[] nums) { //他的本质还是一个数组 List<List<Integer>> res =new ArrayList<>(); //首先是特判 int len = nums.length; if(len==0){ return res; } //记录元素的使用情况,空间换时间 boolean[] used =new boolean[len]; //记录当前路径 List<Integer> path =new ArrayList<>(); dfs(nums,len,0,path,used,res); return res; } //depth 是记录当前深度 public void dfs(int[] nums,int len,int depth,List<Integer> path,boolean[] used,List<List<Integer>>res){ //回溯首先就需要写回溯的终止条件 if(depth==len){ //到了最后一层了,把当前path记录下来吧。 res.add(new ArrayList<> (path)); } for(int i=0 ;i<len;i++){ //首先要确保这个元素没有被用过 if(!used[i]){ path.add(nums[i]); used[i]=true;//标记状态 //深度加一 dfs(nums,len,depth+1,path,used,res); //最后一层已经搜索完了,会回到倒数第二层 dfs这条语句执行完 //状态重置,与上面是相反的 used[i]=false; path.remove(path.size() - 1); } } } }上面这种情况是没有重复元素的,那如果存在重复元素的时候怎么办?剪枝操作!
剪枝操作的前提是:元素需要排序!!!
class Solution { public List<List<Integer>> permute(int[] nums) { //他的本质还是一个数组 List<List<Integer>> res =new ArrayList<>(); //首先是特判 int len = nums.length; if(len==0){ return res; } // 排序(升序或者降序都可以),排序是剪枝的前提 Arrays.sort(nums); //记录元素的使用情况,空间换时间 boolean[] used =new boolean[len]; //记录当前路径 List<Integer> path =new ArrayList<>(); dfs(nums,len,0,path,used,res); return res; } //depth 是记录当前深度 public void dfs(int[] nums,int len,int depth,List<Integer> path,boolean[] used,List<List<Integer>>res){ //回溯首先就需要写回溯的终止条件 if(depth==len){ //到了最后一层了,把当前path记录下来吧。 res.add(new ArrayList<> (path)); } for(int i=0 ;i<len;i++){ //首先要确保这个元素没有被用过 if(!used[i]){ if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) { continue; } path.add(nums[i]); used[i]=true;//标记状态 //深度加一 dfs(nums,len,depth+1,path,used,res); //最后一层已经搜索完了,会回到倒数第二层 dfs这条语句执行完 //状态重置,与上面是相反的 used[i]=false; path.remove(path.size() - 1); } } } }来看看这句话
//剪枝 if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) { continue; } nums[i] == nums[i - 1 两次的元素相同!used[i - 1] 这里为什么有这个!,原因是当我搜索到重复元素i时,我前一个相同的元素i-1的状态刚刚被重置为true