给定一个 没有重复 数字的序列,返回其所有可能的全排列。
这道题很好理解,如果自己在纸上写的话也很好写:比如把123写在纸上,然后1放在最前面,然后是2,3,然后把3拿掉,2拿掉,放3和2…这样反复地先写一个排列,拿掉几个数字再组成另一个排列,最终得到所有的排列情况,在算法中,这叫做“回溯法”。
所谓回溯法,顾名思义就是在搜索过程中不停回溯,这样一看就和深度优先搜索有着千丝万缕的联系,而这道题目中的回溯法其实就是模拟了在纸上反复试错的过程:通过递归函数,其参数中包括当前深度/数组/结果数组/当前路径/数组长度以及一个存储访问情况的数组。递归分为两部分,一部分是当前深度与数组长度相等时,则在结果中加入当前路径并return,然后进行回溯:体现在代码中是将当前元素的visited值变为0,并将其从路径中删除。
public List<List<Integer>> permute(int[] nums) {
int len = nums.length;
List<List<Integer>> res = new ArrayList<List<Integer>>();
int []visited = new int[len];
List<Integer> path = new ArrayList<>();
for(int i = 0 ;i < len;i++){
visited[i] = 0;
}
dfs(res,0,len,nums,visited,path);
return res;
}
void dfs(List<List<Integer>> res,int depth,int len,int[]nums,int[]visited,List<Integer>path){
if(depth == len){
res.add(new ArrayList<>(path));
return ;
}
for(int i = 0;i<len;i++){
if(visited[i]!=1){
visited[i] = 1;
path.add(nums[i]);
dfs(res,depth+1,len,nums,visited,path);
visited[i] = 0;
path.remove(path.size()-1);
}
}
}
代码中值得注意的点为 res.add(new ArrayList<>(path));如果不这么写的话,res最后会由几个空列表组成,这是因为java的传递机制,res.add(path)表示将path指向的列表变量传递给res,但path是一直在变的对象,且最终会变为空,因此每次添加值的时候需要给当前path进行一次拷贝,相当于进行一次快照并存储。
另外,for循环内的执行和递归顺序也需要多理解,虽然自己画图很好懂,但是体现在代码中的执行顺序就要慢慢想了。