zoukankan      html  css  js  c++  java
  • [LeetCode#90]Subsets II

    Problem:

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

    Analysis:

    At first glance, you would follow the same complex routine to solve permutation problem. 
    1. we need a indicator for position to check base case.
    2. we need a used array to indicate which words have already been used.
    3. we need a checking mechanism, so as to avoid palcing same value at the same position twice.
    
    Thus, we reach the following ugly solution.
    
        static public List<List<Integer>> subsetsWithDup(int[] nums) {
            List<List<Integer>> ret = new ArrayList<List<Integer>> ();
            if (nums == null || nums.length == 0)
                return ret;
            Arrays.sort(nums);
            ArrayList<Integer> path = new ArrayList<Integer> ();
            boolean[] used = new boolean[nums.length];
            helper(0, 0, nums, used, path, ret);
            return ret;
        }
        
        static public void helper(int pos, int index, int[] nums, boolean[] used, ArrayList<Integer> path, List<List<Integer>> ret)     {
            if (pos == nums.length) {
                ret.add(new ArrayList<Integer> (path));
                return;
            }
            for (int i = index; i < nums.length; i++) {
                if (i > 0 && nums[i] == nums[i-1] && !used[i-1]) continue;
                if (!used[i]) {
                    used[i] = true;
                    helper(pos+1, i+1, nums, used, path, ret);
                    path.add(nums[i]);
                    helper(pos+1, i+1, nums, used, path, ret);
                    path.remove(path.size()-1);
                    used[i] = false;
                }
            }
        }
        
    To make things worse, it is not right for the following case.
    nums = [1, 1]
    output: [], [1], [1], [1, 1]
    expected: [], [1], [1, 1]
    The problem was caused by a ridiculous logic error:
            [1, 1]
        [1]
            [1]
    []
            [1]
        []
            []
    And this error is hard not solve, cause we have already solved the problem of placing two different elements with the same value at the same position.
    
    Actually, this problem could be sovled in a very very elegant way, without any need to record position, used array!!! The only thing we should keep in mind is that: we have no exact position concept now, a helper process is to place a element at a positon, but we do not know the eact position.
    
    Since the result must in no-descending order, we must sort the nums first. What's more, it is the tool of avoding duplicates!!!
    Arrays.sort(nums);
    
    1. Start from empty path: []
    2. For each search enter into the helper, we add it into result set. (That's the definition of subset. Right???)
    ret.add(new ArrayList<Integer> (path));
    3. Then we try to select a element from [start, nums.length - 1] to append it into the current subset.
    for (int i = start; i < nums.length; i++) {
        if (i > start && nums[i] == nums[i-1]) continue;
        path.add(nums[i]);
        helper(nums, i+1, path, ret);
        path.remove(path.size()-1);
    }
    Note 1: we are trying to place a element for the same position. we should avoid duplicates at here.
    The skill to avoid the duplicate is common. <only the first element share the value was placed>
    if (i > start && nums[i] == nums[i-1]) continue;
    
    Note 2: we do not need used array at here, cause for next placement, we always start from the element after the current placed element.
    path.add(nums[i]);
    helper(nums, i+1, path, ret);
    path.remove(path.size()-1);

    Solution:

    public class Solution {
        public List<List<Integer>> subsetsWithDup(int[] nums) {
            List<List<Integer>> ret = new ArrayList<List<Integer>> ();
            if (nums == null || nums.length == 0)
                return ret;
            ArrayList<Integer> path = new ArrayList<Integer> ();
            Arrays.sort(nums);
            helper(nums, 0, path, ret);
            return ret;
        }
        
        private void helper(int[] nums, int start, ArrayList<Integer> path, List<List<Integer>> ret) {
            ret.add(new ArrayList<Integer> (path));
            for (int i = start; i < nums.length; i++) {
                if (i > start && nums[i] == nums[i-1]) continue;
                path.add(nums[i]);
                helper(nums, i+1, path, ret);
                path.remove(path.size()-1);
            }
        }
    }
  • 相关阅读:
    iOS objc_msgSend 报错解决方案
    不再以讹传讹,GET和POST的真正区别
    HTTP Get请求URL最大长度
    [转]浅论ViewController的加载 -- 解决 viewDidLoad 被提前加载的问题(pushViewController 前执行)
    ASIHTTPRequest-断点续传需要原网站支持!
    iOS关于error can't allocate region的一点发现
    Xcode 5.1.1 与 Xcode 6.0.1 的共存之路(建议大家在升级Xcode 6.0.1 的时候保留Xcode 5.1.1)
    监测uitableview 向上滑动和向下滑动的事件
    Xcode5和6共存时,如何发布应用到商店
    利用MPMoviePlayerViewController 播放视频 iOS
  • 原文地址:https://www.cnblogs.com/airwindow/p/4750014.html
Copyright © 2011-2022 走看看