題目
給定一個可包含重複數字的序列,返回所有不重複的全排列。
示例:
輸入: [1,1,2]
輸出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
分析
該題目和 全排列I 的差別在於:本題目可以包含重複的數字,並且要求返回所有不重複的全排列。
按照常規的思路,我們畫出深度優先搜索樹,並確定路徑和可選列表。
如 nums = [1, 2, 2], 它的深度優先搜索樹如下:
最關鍵的是去重操作:
for (int i = 0; i < candidate.size(); i++) {
if (i != 0 && candidate.get(i) == candidate.get(i - 1)) continue;
int tmp = candidate.remove(i);
path.add(tmp);
permute(res, candidate, path);
path.remove(path.size() - 1);
candidate.add(i, tmp);
}
如:在根節點時,path = {}, candidate = {}, 在 i 指標進行循環時,如果遇到 candidate[i] == candidate[i - 1],那麼進行剪枝,也就是說當 i = 2時,candidate[2] = (candidate[1] = ), 該枝應該被剪掉。(因爲它的 path = {}, candidate = {1, }, 與前面的一枝是完全重複的)。該方法在 子集II 和 三數之和 中都有用到。
代碼
class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
if (nums == null || nums.length == 0) return res;
Arrays.sort(nums);
List<Integer> candidate = new ArrayList<>();
for (int num : nums) candidate.add(num);
permute(res, candidate, new ArrayList<>());
return res;
}
private void permute(List<List<Integer>> res, List<Integer> candidate, List<Integer> path) {
if (candidate.size() == 0) {
res.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < candidate.size(); i++) {
if (i != 0 && candidate.get(i) == candidate.get(i - 1)) continue;
int tmp = candidate.remove(i);
path.add(tmp);
permute(res, candidate, path);
path.remove(path.size() - 1);
candidate.add(i, tmp);
}
}
}