每天一道LeetCode-----找出给定序列的所有子序列

Subsets

原题链接Subsets

每天一道LeetCode-----找出给定序列的所有子序列_第1张图片

给定一个数组序列,找出所有子序列

深度优先扫一遍:)

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> res;
        vector<int> cur;
        dfs(0, nums, cur, res);
        return res;
    }
private:
    void dfs(int i, vector<int>& nums, vector<int>& cur, vector<vector<int>>& res)
    {
        res.emplace_back(cur);
        if(i >= nums.size())
            return;
        for(int j = i; j < nums.size(); ++j)
        {
            cur.push_back(nums[j]);
            dfs(j + 1, nums, cur, res);
            cur.pop_back();
        }
    }
};

原题链接Subsets II

每天一道LeetCode-----找出给定序列的所有子序列_第2张图片
找到给定序列的所有子序列,给定的序列中可能会包含重复元素

解题时需要注意几个地方

  • 容我好好吐槽一下,根本没有说明好伐:(
  • 最后的结果中子序列的顺序无要求,即[1,2,3]和[3,2,1]是相同的
  • 对于重复元素,第二条规定尤为重要,即[4,4,4,1]和[4,4,1,4]是相同的
  • 更重要的是,对于第三条,[1,4,4,4]和[4,4,4,1]以及[4,4,1,4]同样是相同的

用[1,2,3]代替[3,2,1]以及用[1,4,4,4]代替[4,4,1,4]是什么概念,就是说所有子序列可以都是递增的,再往上想就是可以事先对给定序列排序,那解决重复问题就简单多了

在Subsets中,通过深度优先找到了所有的子序列,但是如果序列中有重复元素,需要添加几个限制条件

以序列[4,4,4,1,4]举例,如果不添加限制条件,那么最后的结果可能存在

[4,4,4,1],[4,4,1,4]以及[4,1],[1,4]以及[4,4,4],[4,4,4]

毫无疑问上面二个都是相同的,即结果中出现重复元素,不符合要求

深度优先和回溯在解决重复问题时通常是在下次递归之前判断当前要添加到结果集中的元素是否应该被添加到结果集中,针对Subsets的模板


class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        //std::sort(nums.begin(), nums.end());
        vector<vector<int>> res;
        vector<int> cur;
        dfs(nums, 0, cur, res);
        return res;
    }
private:
    void dfs(vector<int>& nums, int i, vector<int>& cur, vector<vector<int>>& res)
    {
        res.emplace_back(cur);
        for(int j = i; j != nums.size(); ++j)
        {
            //判断是否应该添加到结果集中
            if(...)
            {
                cur.emplace_back(nums[j]);
                dfs(nums, j + 1, cur, res);
                cur.pop_back();        
            }
        }
    }
};

方法就是判断nums[j]是否在[i : j-1]这个范围内出现过,考虑当前遍历到[1,4,4,4,4] (已排序)的下标1(即元素4的位置),在回溯之后遍历的下标改为2(即第二个元素4的位置),这就会重复

因为在遍历第一个4时进入深度优先递归,在递归的过程中已经将所有组合可能都记录到结果中,其中就包括下标组合[1,3,4],那和第二次递归的下标组合[2,3,4]其实是一样的,结果都是[4,4,4]

原因是对于任何重复的元素,只需要考虑第一个即可,假设i, i+1, i+2, …, k是重复元素,那么选择nums[i]和选择nums[i+2]是一样的,因为选择nums[i]时,可以假设递归时不选择nums[i+1],那么就和直接选择nums[i+2]一样了

代码如下


class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        std::sort(nums.begin(), nums.end());
        vector<vector<int>> res;
        vector<int> cur;
        dfs(nums, 0, cur, res);
        return res;
    }
private:
    void dfs(vector<int>& nums, int i, vector<int>& cur, vector<vector<int>>& res)
    {
        res.emplace_back(cur);
        for(int j = i; j != nums.size(); ++j)
        {
            if(j == i || nums[j] != nums[j - 1])
            {
                cur.emplace_back(nums[j]);
                dfs(nums, j + 1, cur, res);
                cur.pop_back();
            }
        }
    }
};

你可能感兴趣的:(LeetCode)