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);
        }
    } 
}

 

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