Leetcode 47.全排列II

题目要求

  • 给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。

示例 1:
输入:nums = [1,1,2]
输出:
[[1,1,2],
[1,2,1],
[2,1,1]]

示例 2:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

回溯法

与Leetcode46类似,区别在于这道题不仅需要树枝去重,还需要树层去重
需要注意的是代码

1
2
3
if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
continue;
}

如果改成used[i - 1] == true也是正确的
这是因为used[i - 1] == true是在树枝上去重,used[i - 1] == false是在树层上去重,树层去重效率更高

used[i-1]==false树层去重
used[i-1]==true树枝去重

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution {
public List<List<Integer>> res = new ArrayList<>();
public List<Integer> path = new ArrayList<>();
public List<List<Integer>> permuteUnique(int[] nums) {
boolean[] used = new boolean[nums.length];
Arrays.fill(used, false);
// 对数组进行排序,让相同的元素在一起,方便去重
Arrays.sort(nums);
backtrack(nums, used);
return res;
}

public void backtrack(int[] nums, boolean[] used) {
if (path.size() == nums.length) {
res.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < nums.length; i++) {
// used[i - 1] == true,说明同⼀树⽀nums[i - 1]使⽤过,实现树枝去重
// used[i - 1] == false,说明used[i-1]是用过后设置为的false,
// 是回溯过去的,即同⼀树层nums[i - 1]使⽤过,也就实现了树层去重
if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
continue;
}
//如果同⼀树⽀nums[i]使⽤过那就直接跳过
if (used[i] == true) continue;
used[i] = true;//标记同⼀树⽀nums[i]使⽤过,防止同一树枝重复使用
path.add(nums[i]);
backTrack(nums, used);
path.remove(path.size() - 1);//回溯,说明同⼀树层nums[i]使⽤过,防止下一树层重复
used[i] = false;//回溯
}
}
}