题目
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); } }
这个时间是最短的。