1. 题目
地址: https://leetcode.com/problems/subsets-ii/
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.
Example:
Input: [1,2,2]
Output:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
2. DFS回溯解法
思路解析:
- 给数组排序
- 当列表的长度小于等于数组长度的时候,添加到结果列表
- 如果当前元素与上个元素相同,则忽略。
package backtracking;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
// https://leetcode.com/problems/subsets-ii/
public class SubsetsII {
public static void main(String[] args) {
int[] nums = {1,2,2};
SubsetsII obj = new SubsetsII();
List<List<Integer>> resultList = obj.subsetsWithDup(nums);
System.out.println(Arrays.toString(resultList.toArray()));
}
public List<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> resultList = new ArrayList<List<Integer>>();
// dfs
dfs(nums, resultList, new ArrayList<Integer>(), 0);
return resultList;
}
private void dfs(int[] nums, List<List<Integer>> resultList, List<Integer> list, int start) {
if (start <= nums.length) {
resultList.add(list);
}
int i = start;
while (i < nums.length) {
list.add(nums[i]);
dfs(nums, resultList, new ArrayList<Integer>(list), i + 1);
list.remove(list.size() - 1);
i++;
while (i < nums.length && nums[i] == nums[i - 1]) {
i++;
}
}
}
}
3. 回溯解法用for循环
解题思路跟上面的一样,去重判断语句if (i > start && nums[i] == nums[i - 1]) continue;
在回溯算法里面比较通用,所以还是用这种方式同样可以解决。
public List<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> resultList = new ArrayList<List<Integer>>();
// dfs
dfsWithFor(nums, resultList, new ArrayList<Integer>(), 0);
//subsetsWithDupHelper(nums, resultList, new ArrayList<Integer>(), 0);
return resultList;
}
private void dfsWithFor(int[] nums, List<List<Integer>> resultList, List<Integer> list, int start) {
// exit
if (start <= nums.length) {
resultList.add(new ArrayList<>(list));
}
for (int i = start; i < nums.length; i++) {
// duplicate case
if (i > start && nums[i] == nums[i - 1]) {
continue;
}
// pick up
list.add(nums[i]);
dfsWithFor(nums, resultList, list, i + 1);
// not pick up
list.remove(list.size() - 1);
}
}
4. 顺序执行
解题思路:
- 对数组nums进行升序排序
- 挨个遍历数组nums的元素
- 如果当前元素与上个元素不相同,则从位置0开始对已有结果列表resultList进行遍历,把当前元素
nums[i]
都加入到子列表中。 - 如果当前元素与上个元素相同,则从上回的结果列表的大小开始,这样子可以过滤掉相同的元素。
public List<List<Integer>> subsetsWithDupIterate(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> resultList = new ArrayList<List<Integer>>();
List<Integer> list = new ArrayList<Integer>();
resultList.add(list);
int duplicateStart = 0;
for (int i = 0; i < nums.length; i++) {
int begin = 0;
int size = resultList.size();
if (i > 0 && nums[i] == nums[i - 1]) {
begin = duplicateStart;
}
for (int k = begin; k < size; k++) {
List<Integer> newList = new ArrayList<Integer>(resultList.get(k));
newList.add(nums[i]);
resultList.add(newList);
}
duplicateStart = size;
}
return resultList;
}