参考自:https://my.oschina.net/u/3744313/blog/1923933
前提:没有重复数字的序列
解法一:
基于回溯的思想,借助一个辅助数组用于记录访问状态。
相关讲解视频:https://www.youtube.com/watch?v=oCGMwvKUQ_I
List<List<Integer>> result = new ArrayList<>();
public List<List<Integer>> permute(int[] nums) {
boolean[] map = new boolean[nums.length];
dfs(nums, map, new ArrayList<>());
return result;
}
public void dfs(int[] nums, boolean[] visited, List<Integer> tmp) {
if (tmp.size() == nums.length)
result.add(new ArrayList<>(tmp));
else {
// 否则,开始循环遍历,按照0,1,2..的顺序依次选择起点,然后遍历
for (int i = 0; i < nums.length; i++) {
if (visited[i])// 若该点已经被访问过了,则跳过访问下一个点
continue;
else {
// 若没被访问过,那么先标记为访问了,然后将其加入 tmp 中,
//等得到一个全排列的结果时加入到 result 中
visited[i] = true;
tmp.add(nums[i]);
dfs(nums, visited, tmp);// 递归调用
// 递归结束,还原当前位置的状态(即回溯),使得可以填充下一个元素,
// 从而进行新的组合
tmp.remove(tmp.size() - 1);
// 访问标记还原,使得下次遍历还可以使用该元素
visited[i] = false;
}
}
}
}
例如:对于 [1,2,3]
,有如下部分过程示例
dfs(mums, visited, tmp())
i = 0: v[0] = true
tmp = (1)
dfs(mums, visited, tmp(1))
i = 0: continue
i = 1: v[1] = true
tmp = (1, 2)
dfs(mums, visited, tmp(1, 2))
i = 0: continue
i = 1: continue
i = 2: v[2] = true
tmp = (1, 2, 3)
dfs(mums, visited, tmp(1, 2, 3))
add to result list
after tmp.remove(3 -1) tmp = (1, 2)
v[2] = false
loop end
// 递归结束,还原 tmp[1],去掉 tmp(1, 2) 的第二个元素
// 即回溯,得到 tmp = (1),使得 tmp[1] 位置可以填充下一个元素
after tmp.remove(2 -1) tmp = (1)
v[1] = false
i = 2: v[2] = true
...
解法二:
交换解法,核心部分就是将各个位都与后面的每一个位都交换一次,并且这种交换是累积式的
public List<List<Integer>> permute(int[] nums) {
helper(nums, 0);
return result;
}
public void helper(int[] nums, int i){
// 找到转置完成后的解,将其存入列表中
if(i == nums.length - 1){
List<Integer> list = new LinkedList<Integer
for(int j = 0; j < nums.length; j++){
list.add(nums[j]);
}
result.add(list);
}
// 将当前位置的数跟后面的数交换,并搜索解
for(int j = i; j < nums.length; j++){
swap(nums, i, j);// 交换位置
helper(nums, i + 1);
swap(nums, i, j);// 还原前面交换的位置
}
}
private void swap(int[] nums, int i, int j){
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}