78. Subsets I & II

来源:互联网 发布:淘宝客如意投怎么设置 编辑:程序博客网 时间:2024/05/19 03:29

QUESTION

Given a set of distinct integers, nums, return all possible subsets.

Note: The solution set must not contain duplicate subsets.

For example,

If nums = [1,2,3], a solution is:

[  [3],  [1],  [2],  [1,2,3],  [1,3],  [2,3],  [1,2],  []]

THOUGHT I

利用位操作,很好理解,当某一位为1的时候代表可以加入到集合当中去。对于数组[1,2,3],可以用一个下标0和1表示是否选择该数字,0表示未选择,1表示选中,那么每一组3个0和1的组合表示一种选择,3位共有8种选择,分别是:

000 对应[] 001 对应[3] 010 对应[2] 011 对应[2,3] 100 … 101 110 111

那么上面为1的位表示数组中该位被选中。 那么只需要遍历0到1<< length中的数,判断每一个数中有那几位为1,为1的那几位即会构成一个子集中的一个元素。

CODE
public class Solution {    public List<List<Integer>> subsets(int[] nums) {        ArrayList<List<Integer>> result = new ArrayList<List<Integer>>();        for(int i = 0;i < 1 << nums.length;i++){            ArrayList<Integer> temp = new ArrayList<Integer>();            for(int j = 0;j < nums.length;j++){                if((i & (1 << j)) != 0 )                    temp.add(nums[j]);            }            result.add(new ArrayList(temp));        }        return result;    }}
RESULT

runtime complexity is O(2^n),space complexity is O(1);

SPECIAL ATTENTION
  • == 还有!= 的优先级要高于&;
== has higher priority than &. You might want to wrap your operations in () to specify your own priority.((a[0] & 1) == 0)Similarly for all parts of the if condition.
  • 把一个List加入到另一个List当中去,如果List发生变化,存入的结果也会发生变化,也就是传址引用,我们的做法是new一个新的List;
  • 注意阶段性空间的初始化位置问题;

THOUGHT II

基本思路循环+dfs,生成指定元素数目(0,1,2,…array.size()个元素)的组合。

CODE
public class Solution {    public List<List<Integer>> subsets(int[] nums) {        ArrayList<List<Integer>> result = new ArrayList<List<Integer>>();        ArrayList<Integer> temp = new ArrayList<Integer>();        result.add(temp);        if(nums.length == 0)            return result;        for(int i = 1;i <= nums.length;i++){            dfs(result,temp,nums,i,0);        }        return result;    }    public void dfs(ArrayList<List<Integer>> result,ArrayList<Integer> temp,int[] nums,int len,int start){        if(temp.size() == len){//边界条件            result.add(new ArrayList<Integer>(temp));            return;        }        for(int i = start;i < nums.length;i++){            temp.add(nums[i]);            dfs(result,temp,nums,len,i+1);            temp.remove(temp.size() - 1);        }    }}
RESULT

递归类的时间复杂度不会算;

THOUGHT III 二刷

这里有一个通用的解法,适用于回溯问题A general approach to backtracking questions in Java (Subsets, Permutations, Combination Sum, Palindrome Partitioning)

CODE
public class Solution {    public List<List<Integer>> subsets(int[] nums) {        List<List<Integer>> res = new ArrayList<>();        if(nums == null || nums.length == 0)            return res;        Arrays.sort(nums);        List<Integer> tempList = new ArrayList<>();        helper(res,tempList,nums,0);        return res;    }    private void helper(List<List<Integer>> res,List<Integer> tempList,int[] nums,int start){        res.add(new ArrayList<>(tempList));        for(int i = start;i < nums.length;i++){            tempList.add(nums[i]);            helper(res,tempList,nums,i + 1);            tempList.remove(tempList.size() - 1);        }    }}

QUESTION II

Given a collection of integers that might contain duplicates, nums, return all possible subsets.

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],  []]
THOUGHTS

比上个解法多了一个排序,多了一个去重。这里不是很理解为什么不排序不能通过。没有要求从小到大输出啊。

CODE
public class Solution {    public List<List<Integer>> subsetsWithDup(int[] nums) {        ArrayList<List<Integer>> result = new ArrayList<List<Integer>>();        ArrayList<Integer> temp = new ArrayList<Integer>();        result.add(temp);        if(nums.length == 0)            return result;        Arrays.sort(nums);        for(int i = 1;i <= nums.length;i++){            dfs(result,temp,nums,i,0);        }        return result;    }    public void dfs(ArrayList<List<Integer>> result,ArrayList<Integer> temp,int[] nums,int len,int start){        if(temp.size() == len){//边界条件            result.add(new ArrayList<Integer>(temp));            return;        }        for(int i = start;i < nums.length;i++){            temp.add(nums[i]);            dfs(result,temp,nums,len,i+1);            temp.remove(temp.size() - 1);            while(i<(nums.length - 1)&&nums[i] == nums[i+1]) {                  i++;              }          }    }}

THOUGHT II

用回溯法来进行遍历,别忘了要先排序

CODE
public class Solution {    public List<List<Integer>> subsetsWithDup(int[] nums) {        List<List<Integer>> res = new ArrayList<>();        if(nums == null || nums.length == 0)            return res;        Arrays.sort(nums);        List<Integer> temp = new ArrayList<>();        helper(res,temp,nums,0);        return res;    }    private void helper(List<List<Integer>> res,List<Integer> temp,int[] nums,int start){        res.add(new ArrayList<>(temp));        for(int i = start;i < nums.length;i++){            if(i > start && nums[i] == nums[i - 1])                 continue;            temp.add(nums[i]);            helper(res,temp,nums,i + 1);            temp.remove(temp.size() - 1);        }    }}
0 0
原创粉丝点击