1. 程式人生 > >LeetCode90求集合的所有子集,集合是可以重複的

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

}

這個時間是最短的。