- 题目:一个包含重复元素的数组,求该数组的全部唯一的组合
- 难度:Medium
- 思路:求元素的组合序列,必然用回溯法来求,但这里的问题是数组的元素包含重复元素,但是组合列表不能有重复,所以重点在于怎么添加限制条件来排除组合列表出现的重复组合。
代码:
我的代码很不友好,代码量太大
我用来排除出现重复列表的方法是: 1.在为组合添加第一个元素的时候,加上一个判断(if nums[i] == nums[i-1] then i++) 2.在回溯的方法里,用一个set来存储已经访问过的数组下标,然后,判断该下标元素是否被访问过了,访问过的元素不应该添加到这个组合中 通过上面两步的过滤后,还会出现一个问题,组合中的后面元素是相同,那就出现组合元素相同的情况。例如,数组为1,1,2 那么只用上面两个过滤,则会出现结果为[[1,1,2],[1,2,1],[2,1,1],[2,1,1]] 于是再在回溯方法中加上一个判断条件 3. if(nums[i] == nums[i-1] && nums[i-1] not in set) 这说明值相同的元素中的第一个如果不在组合中,那么这些相同的元素都不应该被访问添加到组合中,否则出现了重复(换句话说,相同的一串元素只有一种组合方式,跟顺序无关)
public class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
if(nums == null || nums.length == 0) {
return result;
}
Arrays.sort(nums);
for(int i = 0; i < nums.length; i++) {
while(i > 0 && i < nums.length && nums[i] == nums[i-1]){
i++;
}
if(i < nums.length){
List<Integer> tmp = new ArrayList<>();
tmp.add(nums[i]);
LinkedHashSet<Integer> set = new LinkedHashSet<>();
set.add(i);
backtrack(result, tmp, nums, set);
}
}
return result;
}
public void backtrack(List<List<Integer>> list, List<Integer> tmp, int[] nums, LinkedHashSet<Integer> set) {
if(tmp.size() == nums.length) {
list.add(new ArrayList<>(tmp));
return;
}else {
for(int i = 0; i < nums.length; i++) {
if(set.contains(i)){
continue;
}
if( i > 0 && nums[i] == nums[i-1] && !set.contains(i-1)){
continue;
}
set.add(i);
tmp.add(nums[i]);
backtrack(list, tmp, nums, set);
set.remove(i);
tmp.remove(tmp.size()-1);
}
}
}
}
通过分析,上述三个过滤条件,发现第1点和第3点其实做的是同一件事,不管对于组合中的第1个元素还是其他元素,数组中相同元素都只能有一个下标被添加到组合中,于是有了一下的改进代码
改进代码
public class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
if(nums == null || nums.length == 0) {
return result;
}
Arrays.sort(nums);
backtrack(result, new ArrayList<>(), nums, new LinkedHashSet<Integer>());
return result;
}
public void backtrack(List<List<Integer>> list, List<Integer> tmp, int[] nums, LinkedHashSet<Integer> set) {
if(tmp.size() == nums.length) {
list.add(new ArrayList<>(tmp));
return;
}else {
for(int i = 0; i < nums.length; i++) {
if(set.contains(i)){
continue;
}
if( i > 0 && nums[i] == nums[i-1] && !set.contains(i-1)){
continue;
}
set.add(i);
tmp.add(nums[i]);
backtrack(list, tmp, nums, set);
set.remove(i);
tmp.remove(tmp.size()-1);
}
}
}
}
数组中没有重复元素的排列组合
Permutions