题目
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.
For example,
If nums = [1,2,2]
, a solution is:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
因为可以重复,所以首先应该进行排序,Arrays.sort()函数,我以前没用过,现在知道有这样的一个函数了,但是我自己的写的冒泡排序比这个快,不知道为啥呀。
首先,看看我的两个逻辑,其实依赖map函数有点儿费时:
package leetcode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class LC90SubSetsII {
public static List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> ret = new ArrayList<List<Integer>>();
Map<String,Integer> map = new HashMap<String,Integer>();
int len = nums.length;
if(len == 0){
return ret;
}
Arrays.sort(nums);//两种排序的对比
/*for(int i = 0;i<len-1;i++){
int min = nums[i];
int t=i;
for(int j=i+1;j<len;j++){
if(nums[j]<min){
min=nums[j];
t=j;
}
}
if(t!=i){
nums[t]=nums[i];
nums[i]= min;
}
}*/
for(int i=0;i<len;i++){
int n = ret.size();
for(int j=0;j<n;j++){
List<Integer> temp = ret.get(j);
List<Integer> list = new ArrayList<Integer>();
String str = "";
for(int k=0;k< temp.size();k++){
list.add(temp.get(k));
str=str+temp.get(k);
}
list.add(nums[i]);
str=str+nums[i];
if(map.containsKey(str)){
continue;
}
map.put(str, 1);
ret.add(list);
}
List<Integer> list = new ArrayList<Integer>();
if(map.containsKey(String.valueOf(nums[i]))){
continue;
}
map.put(String.valueOf(nums[i]), 1);
list.add(nums[i]);
ret.add(list);
}
List<Integer> list = new ArrayList<Integer>();
ret.add(list);
return ret;
}
public static void main(String[] args) {
int[] nums={2,2,1,2};
List<List<Integer>> list = subsetsWithDup(nums);
for(int i =0;i<list.size();i++){
for(int j =0;j<list.get(i).size();j++){
System.out.print(list.get(i).get(j));
}
System.out.println();
}
System.out.println(list.size());
}
}
于是就又想了个办法,不用map的既然都排好序了,那么相同的必定都挨在一起了;对于相同的来说,只能增加包含这个数字的集合的基础上再次的增加这个数。于是具体代码如下:
package leetcode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class LC90SubSetsIV {
public static List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> ret = new ArrayList<List<Integer>>();
Map<String,Integer> map = new HashMap<String,Integer>();
int len = nums.length;
if(len == 0){
return ret;
}
Arrays.sort(nums);
List<List<Integer>> lastlist = new ArrayList<List<Integer>>();
for(int i=0;i<len;i++){
int n = ret.size();
if(i-1>0 && nums[i]==nums[i-1]){//相同的情况
List<List<Integer>> lastdata = new ArrayList<List<Integer>>(lastlist);//但我估计这个费时就废在这段了
int l=lastdata.size();
lastlist.clear();//清空,为的就只保留增加的。
for(int j=0;j<l;j++){
List<Integer> temp = lastdata.get(j);
List<Integer> list = new ArrayList<Integer>(temp);
list.add(nums[i]);
ret.add(list);
lastlist.add(list);
}
}else{
lastlist.clear();
for(int j=0;j<n;j++){
List<Integer> temp = ret.get(j);
List<Integer> list = new ArrayList<Integer>(temp);
list.add(nums[i]);
ret.add(list);
lastlist.add(list);
}
List<Integer> list = new ArrayList<Integer>();
if(map.containsKey(String.valueOf(nums[i]))){
continue;
}
map.put(String.valueOf(nums[i]), 1);
list.add(nums[i]);
ret.add(list);
lastlist.add(list);
}
}
List<Integer> list = new ArrayList<Integer>();
ret.add(list);
return ret;
}
public static void main(String[] args) {
int[] nums={2,2,1,3};
List<List<Integer>> list = subsetsWithDup(nums);
for(int i =0;i<list.size();i++){
for(int j =0;j<list.get(i).size();j++){
System.out.print(list.get(i).get(j));
}
System.out.println();
}
System.out.println(list.size());
}
}
下面就是递归的办法,这个时间是最短的,我暂时估计是因为地址指针的使用:
package leetcode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class LC90SubSetsV {
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> result = new ArrayList<List<Integer>>();
if (nums == null || nums.length == 0) {
return result;
}
Arrays.sort(nums);
helper(result, new ArrayList<Integer>(), nums, 0);
return result;
}
private void helper(List<List<Integer>> result, List<Integer> cur, int[] nums, int index) {
if (nums.length == index) {
result.add(new ArrayList<Integer>(cur));
return;
}
cur.add(nums[index]);//要了这个数字
helper(result, cur, nums, index + 1);
cur.remove(cur.size() - 1);//和不要这个数字
while (index + 1 < nums.length && nums[index + 1] == nums[index]) {
index++;
}
helper(result, cur, nums, index + 1);
}
}
这个时间是最短的。
2021年6月21
public List<List<Integer>> subsetsWithDup(int[] nums) {
sortACS(nums);
int len=nums.length;
List<List<Integer>> ret=new ArrayList<>();
List<Integer> list= new ArrayList<>();
ret.add(list);
List<List<Integer>> retLast=new ArrayList<>();
for(int i=0;i<len;i++){
List<List<Integer>> temp=new ArrayList<>(ret);
if(i>0&&nums[i]==nums[i-1]){
List<List<Integer>> lastTemp=new ArrayList<>();//只增加上次新增的部分
for(int k=0;k<retLast.size();k++){
List<Integer> tlist= new ArrayList<>(retLast.get(k));
tlist.add(nums[i]);
lastTemp.add(tlist);
temp.add(tlist);
}
retLast=lastTemp;
}else{
retLast=new ArrayList<>();
for(int j=0;j<ret.size();j++){
List<Integer> tlist= new ArrayList<>(ret.get(j));
tlist.add(nums[i]);
temp.add(tlist);
retLast.add(tlist);
}
}
ret=temp;
}
return ret;
}
public void sortACS(int[] nums){
int len=nums.length;
for(int i=0;i<len-1;i++){
for(int j=0;j<len-1;j++){
if(nums[j]>nums[j+1]){
int t=nums[j+1];
nums[j+1]=nums[j];
nums[j]=t;
}
}
}
}