题目
Given a collection of integers that might contain duplicates, nums, return all possible subsets (the power set).
Note: The solution set must not contain duplicate subsets.
我的想法
这道题与78. Subsets基本一样,不过需要滤去相同项,但是两种方法速度都很慢。因为虽然没有吧重复的加入到list,但是进行了重复的遍历
方法一:累加法
在78题的基础上,加上相同项的判断即可
class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
res.add(new ArrayList<>());
Arrays.sort(nums); //必须先排序
for(int n: nums) {
int size = res.size();
for(int i = 0; i < size; i++) {
List temp = new ArrayList<>(res.get(i));
temp.add(n);
if(res.indexOf(temp) != -1) continue; //如果能在res中找到,则跳过
else res.add(temp);
}
}
return res;
}
}
方法二:Backtracking
class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
backtrack(0, nums, new ArrayList<>(), res);
return res;
}
private void backtrack(int start, int[] nums, List<Integer> temp, List<List<Integer>> res) {
if(res.indexOf(temp) == -1) res.add(new ArrayList<>(temp));
for(int i = start; i < nums.length; i++) {
temp.add(nums[i]);
backtrack(i+1, nums, temp, res);
temp.remove(temp.size() - 1);
}
}
}
解答
leetcode solution 1: Backtracking
这里将不必要的遍历也进行了跳过,使得速度大幅提升
public class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
Arrays.sort(nums);
backtrack(list, new ArrayList<>(), nums, 0);
return list;
}
private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums, int start){
list.add(new ArrayList<>(tempList));
for(int i = start; i < nums.length; i++){
//如果nums[i] == nums[i-1],则nums[i]其后的所有情况
//均在nums[i-1]中已经遍历过,可以直接跳过
if(i > start && nums[i] == nums[i-1]) continue;
tempList.add(nums[i]);
backtrack(list, tempList, nums, i + 1);
tempList.remove(tempList.size() - 1);
}
}
}
根据solution1,可以对我的方法一进行修改
class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
res.add(new ArrayList<>());
Arrays.sort(nums);
int countAdd = 0;
for(int n = 0; n < nums.length; n++) {
int size = res.size();
int i = 0;
//如果与前项相同,则只需在前项的新加项的基础上再做运算即可
if(n > 0 && nums[n] == nums[n-1]) i = size - countAdd;
countAdd = 0;
for(; i < size; i++) {
List temp = new ArrayList<>(res.get(i));
temp.add(nums[n]);
res.add(temp);
countAdd++;
}
}
return res;
}
}