题目链接
思路:
此题的思路与46题全排列一致,只是在处理过程中需要排除掉重复的排列,这是因为所给数组中存在着重复的数字。
首先需要给数组排序,以便将重复的值都排在相邻的位置,这样进行去重的时候就会方便很多。
在回溯算法中去重时,若当前位置的数等于前一个位置的数,并且前一个位置的数没有使用过(这块没有使用过是因为在之前的回溯中已经被撤销了选择,实际上在之前的回溯中已经使用过了,为了避免重复,故需要不相等的数才行),那么就应该跳过这个数,进行下一个数的搜索。
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> ans = new ArrayList<>();
if (nums == null || nums.length < 1) {
return ans;
}
Arrays.sort(nums);
boolean[] used = new boolean[nums.length];
dfs(nums, 0, used, new ArrayList<Integer>(), ans);
return ans;
}
private void dfs(int[] nums, int depth, boolean[] used,
List<Integer> path, List<List<Integer>> ans) {
if (depth == nums.length) {
ans.add(new ArrayList<Integer>(path));
return;
}
for (int i = 0; i < nums.length; i++) {
// 若当前位置的数等于前一个位置的数,并且前一个位置的数没有使用过
// 这块没有使用过是因为在之前的回溯中已经被撤销了选择,
// 实际上在之前的回溯中已经使用过了,为了避免重复,
// 故需要不相等的数才行
if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) {
continue;
}
// 若当前数没有被使用过
if (!used[i]) {
// 选择当前数
used[i] = true;
path.add(nums[i]);
// 寻找下一个位置的数
dfs(nums, depth + 1, used, path, ans);
// 撤销选择
used[i] = false;
path.remove(path.size() - 1);
}
}
}