详情链接:Leecode 47.全排列II
1.问题思路
这里有重复元素,对于重复元素如何进行剪枝这点弄明白,这道题就迎刃而解了。
重复元素存在如下情况:
① 相同层,出现了相同的元素,需要进行剪枝。
② 不同层,出现了相同的元素,需要进行剪枝。
这里使用一个used数组来记录使用过的元素,在当前层使用完后释放。
① 遵循递归公式,选择递归退出条件,path.size=nums.length
② 对于每层的广度优先遍历需要过滤掉已经使用过的元素
2.代码实现
class Solution {
LinkedList<List<Integer>> result = new LinkedList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> permuteUnique(int[] nums) {
Arrays.sort(nums); // 这里排序是因为需要剔除重复元素,如果数组无序则不好剔除
boolean[] used = new boolean[nums.length];
dfs(nums, used);
return result;
}
public void dfs(int[] nums, boolean[] used) {
// 终止条件
if (path.size() == nums.length) {
result.add(new ArrayList<>(path));
return;
}
// 水平遍历
for (int i =0; i < nums.length; i++) {
// 剪枝
// 同层元素不能重复 nums[i] == nums[i-1]
// 不同层不能重复 !used[i-1], 这里为什么使用!, 因为上一层的已经回溯
if (i > 0 && nums[i] == nums[i-1] && !used[i-1]) {
continue;
}
if (!used[i]) {
used[i] = true;
path.add(nums[i]);
// 垂直遍历
dfs(nums, used);
// 回溯
path.removeLast();
used[i] =false;
}
}
}
}