给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/permutations-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
1、此处可能包含重复数字、需要筛去重复的组合,因此数组需要重排序
2、在深度遍历的时候,需要剪枝,即去掉重复的情况
if (i > 0 && nums[i] == nums[i-1] && used[i - 1] == false){
continue;
}
3、used[i-1]==false, 是因为节点在回退时,会将栈末尾的元素移出、且used[i]会置为false,此点需要注意!
boolean[] used;
public List<List<Integer>> permuteUnique(int[] nums){
int len = nums.length;
//存储结果
List<List<Integer>> res = new ArrayList<>();
//数组为空时,返回空
if (len == 0){
return res;
}
//向下遍历时,每选中一个数字,将数字入栈
//向上遍历时,高度-1、且出栈一个数子
Deque<Integer> path = new ArrayDeque<Integer>();
//是否选中元素
used = new boolean[len];
//数组排序,数组排序是剪枝的前提
Arrays.sort(nums);
//进行深度遍历
dfs(nums, len, 0, path, used, res);
return res;
}
private void dfs(int[] nums, int len, int depth, Deque<Integer> path, boolean[] used, List<List<Integer>> res) {
/*
如果树的深度同数组长度,那么是一个正确的结果,将结果返回
*/
if (depth == len){
res.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < len; i++) {
//如果i被使用,跳过本次循环
if (used[i]){
continue;
}
//如果该元素和上一个元素相等,则跳过本次循环(前提:参数nums是有序的)
//user[i-1]==false : 结点在回退时,已经将栈末尾的元素remove、并且used[i] = false;
//剪枝条件
if (i > 0 && nums[i] == nums[i-1] && used[i - 1] == false){
continue;
}
//将该数字添加至path中
path.addLast(nums[i]);
used[i] =true;
dfs(nums,len, depth+1, path, used, res);
path.removeLast();
used[i] = false;
}
}