LeetCode90求集合的所有子集,集合是可以重复的

题目

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);
	    }

}

这个时间是最短的。

阅读更多
个人分类: leetcode
上一篇LeetCode78求集合的子集,集合是不重复的。
下一篇LeetCode72编辑代价:一个字符串通过插入、删除、替换变成另一个字符串的代价
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭