Leetcode: 47. 全排列II

題目

給定一個可包含重複數字的序列,返回所有不重複的全排列。

示例:

輸入: [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 = {1,2^1, 2^2}, 在 i 指標進行循環時,如果遇到 candidate[i] == candidate[i - 1],那麼進行剪枝,也就是說當 i = 2時,candidate[2] = 2^2 (candidate[1] = 2^1), 該枝應該被剪掉。(因爲它的 path = {2^2}, candidate = {1, 2^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);
        }
    } 
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章