zoukankan      html  css  js  c++  java
  • 【Subsets】cpp

    题目:

    Given a set of distinct integers, 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,3], a solution is:

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

    代码:

    class Solution {
    public:
        vector<vector<int>> subsets(vector<int>& nums) {
                const int len = nums.size();
                std::sort(nums.begin(), nums.end());
                vector<vector<int> > ret = Solution::subsubsets(nums, 0, len-1);
                vector<int> none;
                ret.push_back(none);
                return ret;
        }
        static vector<vector<int> > subsubsets(vector<int>& nums, int begin, int end)
        {
                vector<vector<int> > ret;
                if ( begin>end ) return ret;
                for ( int i = begin; i <=end; ++i )
                {
                    // puts the curr value in
                    vector<int> curr;
                    curr.push_back(nums[i]);
                    ret.push_back(curr);
                    // get the subset
                    vector<vector<int> > subset = Solution::subsubsets(nums, i+1, end);
                    for ( int j = 0; j < subset.size(); ++j )
                    {
                        //ret.push_back(subset[j]);
                        subset[j].insert(subset[j].begin(), nums[i]);
                        ret.push_back(subset[j]);
                    }
                }
                return ret;
        }
    };

    tips:

    每层递归的任务是活的传入数组的全部子集

    1. 留出第i个元素

    2. 把i+1到end的元素送到下一层递归

    3. 递归终止条件是begin>end

    返回下一集全部子集后,算上第i个元素后的全部集合如下:

    1)第i个元素单独算一个

    2)第i个元素 + 子集中每个元素

    这样递归到第0个元素,就得到了全部的非空子集;再根据题目要求补上空集。

    ============================================

    完成之后觉得好像哪里不对。{1,2,3} 如果留下了1传入{2,3}时,这个过程中已经获得了{2,3}全部子集。

    修改后的代码如下:

    class Solution {
    public:
        vector<vector<int>> subsets(vector<int>& nums) {
                const int len = nums.size();
                std::sort(nums.begin(), nums.end());
                vector<vector<int> > ret = Solution::subsubsets(nums, 0, len-1);
                vector<int> none;
                ret.push_back(none);
                return ret;
        }
        static vector<vector<int> > subsubsets(vector<int>& nums, int begin, int end)
        {
                vector<vector<int> > ret;
                if ( begin>end ) return ret;
                // puts the curr value in
                vector<int> curr;
                curr.push_back(nums[begin]);
                ret.push_back(curr);
                // get the subset
                vector<vector<int> > subset = Solution::subsubsets(nums, begin+1, end);
                for ( int j = 0; j < subset.size(); ++j )
                {
                    ret.push_back(subset[j]);
                    subset[j].insert(subset[j].begin(), nums[begin]);
                    ret.push_back(subset[j]);
                }
                return ret;
        }
    };

    tips:

    这个版本整理了逻辑误区。

    ============================

    又学习了一个深搜版本的代码,如下:

    class Solution {
    public:
        vector<vector<int>> subsets(vector<int>& nums) {
                vector<vector<int> > ret;
                std::sort(nums.begin(), nums.end());
                vector<int> tmp;
                Solution::dfs(ret, nums, 0, tmp);
                return ret;
        }
        static void dfs(vector<vector<int> >& ret, vector<int>& nums, int index, vector<int>& tmp)
        {
                if ( index==nums.size() ) { ret.push_back(tmp); return; }
                tmp.push_back(nums[index]);
                Solution::dfs(ret, nums, index+1, tmp);
                tmp.pop_back();
                Solution::dfs(ret, nums, index+1, tmp);
        }
    };

    Tips:

    把集合元素想象成一个二叉树,如下

    每层处理一个元素;往左分支代表加入这个元素;往右分支代表不加入这个元素;最终叶子节点就是全部子集。

    这里需要维护一个层次变量index看是否到叶子了。

    ================================

    再学习一个简单迭代的解法,代码如下:

    class Solution {
    public:
        vector<vector<int>> subsets(vector<int>& nums) {
                vector<vector<int> > ret;
                std::sort(nums.begin(), nums.end());
                vector<int> none;
                ret.push_back(none);
                for ( size_t i = 0; i < nums.size(); ++i )
                {
                    vector<vector<int> > subset = ret;
                    for ( size_t j = 0; j < subset.size(); ++j )
                    {
                        subset[j].push_back(nums[i]);
                        ret.push_back(subset[j]);
                    }
                }
                return ret;
        }
    };

    tips:

    1. 用subset记录上一轮结束后,所有子集;

    2. 考虑subset中所有元素,加上nums[i]元素后多出来的集合,补充到ret中

    这里注意,利用一个中间变量subset来保存ret上一轮的结果(或者保存上一组的指针)。

    仔细想想,这套代码的思路与最开始递归代码的思路正好是逆向的:

    1)递归的代码是留出来当前元素,去寻找其余所有元素组成的子集集合

    2)迭代的代码是每次添加当前元素,并更新所有子集集合,直到添加入最后一个元素

    ================================================

    第二次过这道题,首选的解法是简单迭代解法。这种方法的精髓是在于有一个none,这样每次都能把新元素单独列进来。

    class Solution{
        public:
            static vector<vector<int> > subsets(vector<int>& nums)
            {
                sort(nums.begin(), nums.end());
                vector<vector<int> > ret;
                vector<int> none;
                ret.push_back(none);
                for ( int i=0; i<nums.size(); ++i )
                {
                    vector<vector<int> > tmp = ret;
                    for ( int j=0; j<tmp.size(); ++j )
                    {
                        tmp[j].push_back(nums[i]);
                        ret.push_back(tmp[j]);
                    }
                }
                return ret;
            }
    };

    还用了dfs的解法。

    class Solution {
    public:
            vector<vector<int> > subsets(vector<int>& nums)
            {
                sort(nums.begin(), nums.end());
                vector<vector<int> > ret;
                vector<int> tmp;
                Solution::dfs(nums, ret, 0, tmp);
                return ret;
            }
            static void dfs(
                vector<int>& nums, 
                vector<vector<int> >& ret,
                int index,
                vector<int>& tmp)
            {
                if ( index==nums.size() ) 
                {
                    ret.push_back(tmp);
                    return;
                }
                tmp.push_back(nums[index]);
                Solution::dfs(nums, ret, index+1, tmp);
                tmp.pop_back();
                Solution::dfs(nums, ret, index+1, tmp);
            }
    };

    复习了dfs模板的写法。这个有个点需要注意,就是返回上一层时,一定要保证tmp是‘干净的’,因此,要有pop_back()这个动作。

  • 相关阅读:
    HDOJ 2095 find your present (2)
    HDOJ 2186 悼念512汶川大地震遇难同胞——一定要记住我爱你
    九度 1337 寻找最长合法括号序列
    九度 1357 疯狂地Jobdu序列
    HDOJ 1280 前m大的数
    九度 1343 城际公路网
    九度 1347 孤岛连通工程
    HDOJ 2151 Worm
    九度 1342 寻找最长合法括号序列II
    九度 1346 会员积分排序
  • 原文地址:https://www.cnblogs.com/xbf9xbf/p/4516802.html
Copyright © 2011-2022 走看看