给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
注:本题与46题的区别在于可包含重复数字
题解
题解转载自lieweiwei1419
这一题在「力扣」第 46 题: 全排列 的基础上增加了 序列中的元素可重复 这一条件,但要求:返回的结果又不能有重复元素。
思路是:在遍历的过程中,一边遍历一遍检测,在一定会产生重复结果集的地方剪枝。
画出树形结构如下:重点想象深度优先遍历在这棵树上执行的过程,哪些地方遍历下去一定会产生重复,这些地方的状态的特点是什么?
对比图中标注 ① 和 ② 的地方。相同点是:这一次搜索的起点和上一次搜索的起点一样。不同点是:
标注 ① 的地方上一次搜索的相同的数刚刚被撤销;
标注 ② 的地方上一次搜索的相同的数刚刚被使用。
代码实现方面,在第 46 题的基础上,要加上这样一段代码:
if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) {
continue;
}
完整代码
class Solution {
List<List<Integer>> res = new LinkedList<>();
public List<List<Integer>> permute(int[] nums) {
List<Integer> path = new ArrayList<>();
int len = nums.length;
if (len == 0) {
return res;
}
boolean used[] = new boolean[len];
dfs(nums,0,len,used,path);
return res;
}
public void dfs(int[] nums,int depth,int len,boolean[] used,List<Integer> path){
//递归终止条件:全排列中每一位都被选择
if(depth==len){
//变量 path 所指向的列表在深度优先遍历的过程中只有一份 ,深度优先遍历完成以后,回到了根结点,成为空列表。所以在添加到res时需要做一个拷贝
res.add(new ArrayList<>(path));
//返回
return;
}
for(int i=0;i<len;i++){
if(!used[i]){
path.add(nums[i]);
used[i]=true;
dfs(nums,depth+1,len,used,path);
used[i]=false;
path.remove(path.size() - 1);
}
}
}
}