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

这篇博客探讨了如何使用深度优先搜索找到给定数组序列的所有子序列,特别是处理包含重复元素的情况。作者强调了在解决重复问题时,只需要考虑每个重复元素的第一个实例,并给出了相应的LeetCode题目链接及解题思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Subsets

原题链接Subsets

这里写图片描述

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

深度优先扫一遍:)

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

这里写图片描述
找到给定序列的所有子序列,给定的序列中可能会包含重复元素

解题时需要注意几个地方

  • 容我好好吐槽一下,根本没有说明好伐:(
  • 最后的结果中子序列的顺序无要求,即[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();
            }
        }
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值