• 90. Subsets II


    题目:

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

    Note:

    • Elements in a subset must be in non-descending order.
    • 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],
      []
    ]
    

    链接:  http://leetcode.com/problems/subsets-ii/

    题解:

    Subsets II, 关键是去重复。我们依然使用跟其他dfs +backtracking类似的方法, 当i > pos && nums[i] == nums[i - 1]的时候,跳过当前重复的元素。

    Time Complexity - O(2n), Space Complexity - O(2n)。

    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);
            ArrayList<Integer> list = new ArrayList<>();
            dfs(res, list, nums, 0);
            return res;
        }
        
        private void dfs(List<List<Integer>> res, ArrayList<Integer> list, int[] nums, int pos) {
            res.add(new ArrayList<Integer>(list));
            
            for(int i = pos; i < nums.length; i++) {
                if(i > pos && nums[i] == nums[i - 1])
                    continue;
                list.add(nums[i]);
                dfs(res, list, nums, i + 1);
                list.remove(list.size() - 1);
            }
        }
    }

    二刷:

    跟Subsets I唯一不同的地方就是由重复。 和一刷一样,重点在于去重复。我们只需要在每一层遍历的时候,因为最开始sort过, 只要用i > pos && nums[i] == nums[i - 1]来跳过重复的元素就可以了。

    Java:

    Time Complexity - O(n!), Space Complexity (n2)

    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> list = new ArrayList<>();
            subsetsWithDup(res, list, nums, 0);
            return res;
        }
        
        private void subsetsWithDup(List<List<Integer>> res, List<Integer> list, int[] nums, int pos) {
            res.add(new ArrayList<Integer>(list));
            for (int i = pos; i < nums.length; i++) {
                if (i > pos && nums[i] == nums[i - 1]) {
                    continue;
                }
                list.add(nums[i]);
                subsetsWithDup(res, list, nums, i + 1);
                list.remove(list.size()- 1);
            }
        }
    }

    三刷:

    时间复杂度和空间复杂度真的不可以糊弄...看评论里shenhualong的解释比较好,基本的递归分析。 还要继续好好训练思维。 去重复的方法也可以用在其他类似题目里。

    这里T(n) =  T(n - 1) + T(n - 2) + ... + T(1),  因为 T(n - 1) = T(n - 2) + T(n - 3)... + T(1), 所以T(n) = 2 * T(n - 1),结果就是T(n) = 2n。 对于nums中的每一个数字,我们都要做一个Recursive call,所以这里用了O(n)的时间, 最终结果Time Complexity是 n * 2n。 空间复杂度的话因为我们每次要生成new ArrayList<>(),所以也是2n。

    地里stellari大神的帖子分析得特别好,放在reference里了。

    Java:

    Time Complexity - O(n * 2n), Space Complexity (2n)

    public class Solution {
        public List<List<Integer>> subsetsWithDup(int[] nums) {
            List<List<Integer>> res = new ArrayList<>();
            if (nums == null) return res;
            Arrays.sort(nums);
            getSubsetsWithDup(res, new ArrayList<Integer>(), nums, 0);
            return res;
        }
        
        private void getSubsetsWithDup(List<List<Integer>> res, List<Integer> list, int[] nums, int pos) {
            res.add(new ArrayList<>(list));
            for (int i = pos; i < nums.length; i++) {
                if (i > pos && nums[i] == nums[i - 1]) continue;
                list.add(nums[i]);
                getSubsetsWithDup(res, list, nums, i + 1);
                list.remove(list.size() - 1);
            }
        }
    }

    Reference:

    http://blog.csdn.net/linhuanmars/article/details/24286377

    https://leetcode.com/discuss/46668/recursive-iterative-manipulation-solutions-explanations 

    http://www.1point3acres.com/bbs/thread-117602-1-1.html

  • 相关阅读:
    try catch使用示例
    doxgen生成chm文档和乱码解决方法
    MFC中MessageBox()用法
    UML聚合与组合
    C#网络编程
    单元测试(NUnit)
    Autohotkey
    .NET中的并行
    System.Environment类的使用
    一键VHD
  • 原文地址:https://www.cnblogs.com/yrbbest/p/4437152.html
Copyright © 2020-2023  润新知