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

}

这个时间是最短的。

 

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

            }

        }

    }

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值