链接:
https://leetcode.com/problems/permutations-ii/
大意:
给定一个含重复元素值的数组nums,要求以nums中所有数组成的所有组合(每个组合中每个位置上的数能且只能被使用一次),且不能有重复的组合。例子:
思路:
回溯法。
与前一题不同的是本题数组中含有重复元素 ,需要剔除重复的组合。为了剔除重复的组合,需要对nums进行排序。
首先,组合选用某一个数的大前提肯定是该元素还未被访问。
其次,为了剔除重复,还得满足以下三个条件之一:
(1) 当前元素是第一个元素
(2) 当前元素不是第一个元素,但它与前一个元素不同
(3) 当前元素不是第一个元素,且它与前一个元素相同,但前一个元素已被访问
即若两个元素一样,则必须先访问了前面一个元素,才能访问后面相同的元素(否则的话,会产生重复的组合)
代码:
class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
if (nums.length == 0)
return res;
Arrays.sort(nums); // 排序,更利于去重
boolean[] visited = new boolean[nums.length]; // 用于记录各个位置的元素是否已被访问
dfs(nums, new LinkedList<Integer>(), res, visited);
return res;
}
public void dfs(int nums[], LinkedList<Integer> list, List<List<Integer>> res, boolean[] visited) {
if (list.size() == nums.length) {
res.add(new ArrayList<>(list));
return ;
}
for (int i = 0; i < nums.length; i++) {
/* 首先,要访问该元素,该元素肯定必须得是未被访问的,即 !visited[i]
基于之上的条件,还需满足以下条件之一:
1. 当前元素是第一个元素
2. 当前元素不是第一个元素,但它与前一个元素不同
3. 当前元素不是第一个元素,且它与前一个元素相同,但前一个元素已被访问
即若两个元素一样,则必须先访问了前面一个元素,才能访问后面相同的元素(否则的话,会产生重复的组合)
*/
if (!visited[i] && (i == 0 || nums[i] != nums[i - 1] || visited[i - 1])) {
visited[i] = true;
list.addLast(nums[i]);
dfs(nums, list, res, visited);
visited[i] = false;
list.removeLast();
}
}
}
}
结果:
结论:
总体思想和前一题类似,主要就是判断是否选该元素的条件有了更严格的限制。