47. 全排列 II
难度:中等
题目描述
解题思路
全排列1是没有重复数字生成全排列,这个是有重复数字。先复习一下没有重复数字的写法:
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> temp = new ArrayList<>();
boolean visit[] = new boolean[nums.length];
permuteHelper(nums,res,temp,visit);
return res;
}
public void permuteHelper(int[] nums,List<List<Integer>> res,List<Integer> temp,boolean visit[]) {
if(temp.size() == nums.length) { //满足结束条件
res.add(new LinkedList<Integer>(temp));
return;
}
for (int i = 0;i < nums.length;i++) { //对每个可能选择
if(!visit[i]) {
visit[i] = true;
temp.add(nums[i]); //设置现场
permuteHelper(nums,res,temp,visit); //递归
temp.remove(temp.size()-1); //恢复现场
visit[i] = false;
}
}
}
有重复数字之后,一种思路是用hashset去重,另外一种思路就是用剪纸,分析什么时候会产生重复
参考题解:
回溯搜索 + 剪枝
最后只要对上面的代码添加剪纸条件
// 剪枝条件:i > 0 是为了保证 nums[i - 1] 有意义
// 写 !visit[i - 1] 是因为 nums[i - 1] 在深度优先遍历的过程中刚刚被撤销选择
if (i > 0 && nums[i] == nums[i - 1] && !visit[i - 1]) {
continue;
}
完整代码:
/*
* 47. 全排列 II
* 2020/8/28
* medium
*/
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> res = new LinkedList<>();
List<Integer> temp = new ArrayList<>();
boolean[] visit = new boolean[nums.length];
if(nums.length == 0) {
return res;
}
Arrays.sort(nums);
dfsPermuteUnique(nums,res,temp,visit) ;
return res;
}
public void dfsPermuteUnique(int[] nums,List<List<Integer>> res,List<Integer> temp,boolean[] visit) {
if(temp.size() == nums.length) {
res.add(new LinkedList<>(temp));
return;
}
for (int i = 0; i < nums.length; i++) {
if(visit[i]) {
continue;
}
// 剪枝条件:i > 0 是为了保证 nums[i - 1] 有意义
// 写 !visit[i - 1] 是因为 nums[i - 1] 在深度优先遍历的过程中刚刚被撤销选择
if (i > 0 && nums[i] == nums[i - 1] && !visit[i - 1]) {
continue;
}
temp.add(nums[i]);
visit[i] = true;
dfsPermuteUnique(nums,res,temp,visit);
//回溯撤销选择
temp.remove(temp.size()-1);
visit[i] = false;
}
}