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()这个动作。

  • 相关阅读:
    IDEA 实用功能Auto Import:自动优化导包(自动删除、导入包)
    idea 设置主题
    MySql where 后面使用函数导致索引失效问题
    IDEA报错,注解标红,提示Cannot resolve symbol xxx
    分批更新list
    java.lang.ArithmeticException: Rounding necessary
    Java selenium通过JS直接进行赋值给日期框
    postman接口测试之获取响应数据
    Jenkins集成allure测试报告
    Jenkins配置邮件通知
  • 原文地址:https://www.cnblogs.com/xbf9xbf/p/4516802.html
Copyright © 2011-2022 走看看