代码随想录算法训练营第二十九天|LeetCode 491.递增子序列、LeetCode46.全排列、LeetCode47.全排列 II

一、LeetCode 491.递增子序列

题目链接:491.递增子序列
题目要求找出并返回所有该数组中不同的递增子序列,且所给的数组中的元素是可能重复的。
那么在使用递归和回溯来寻找时,我们要进行树层上的去重操作(树枝上并不需要去重),我们可以创建一个不可重复的哈希表set来标记树层上每个元素是否出现过,然后实现去重。
而且因为递增子序列中至少有两个元素,所以我们在路径数组的大小大于1的时候才能收集有效子集。
代码如下:

class Solution {
    private:
    vector<vector<int>>result;
    vector<int>path;
public:
    void backtraving(vector<int>& nums, int startx) {
        if(path.size() > 1) result.push_back(path);
        unordered_set<int>set;//记录每个元素在本树层上是否出现过
        for (int i = startx; i < nums.size(); i++) {
            if(set.find(nums[i]) != set.end() || (path.size() != 0 && nums[i] < path.back())) continue;//如果当前元素在本树层上出现过或者,当前元素小于路径上最后的元素,则直接跳过本层循环
            set.insert(nums[i]);//否则记录当前元素在本树层上出现过,然后将其放入路径当中,在递归和回溯
            path.push_back(nums[i]);
            backtraving(nums, i + 1);
            path.pop_back();
        }
        return;
    }
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        backtraving(nums, 0);
        return result;

    }
};

二、LeetCode46.全排列

题目链接:46.全排列
这道题如果懂得树枝去重还是比较简单的。
因为题目说明给出的序列是无重复的,所以可以创建一个set哈希表来标记当前所遍历的元素是否在树枝上出现过。
代码如下:

class Solution {
    vector<vector<int>>result;
    vector<int>path;
    unordered_set<int>set;//利用一个哈希表来记录当前元素是否在树枝上出现过
public:
    void backtraving(vector<int>& nums) {
        if(path.size() == nums.size()) {//递归结束条件:如果路径上的元素个数等于原数组大小,说明得到一个全排列,将其收集在结果集里
            result.push_back(path);
            return;
        }
        for(int i = 0; i < nums.size(); i++) {
            if(set.find(nums[i]) != set.end()) continue;//如果当前元素在当前树枝上出现过,则跳过这层循环
            path.push_back(nums[i]);//否则将其放入路径上然后标记下来,再递归和回溯
            set.insert(nums[i]);
            backtraving(nums);
            path.pop_back();
            set.erase(nums[i]);
        }
        return;
    }
    vector<vector<int>> permute(vector<int>& nums) {
        backtraving(nums);
        return result;

    }
};

三、LeetCode47.全排列 II

题目链接:47.全排列 II
这道题需要用树层去重和树枝去重。
当然首先需要对数组进行排序,以便更好的去重。
每遍历到一个树是先判断其是否在数层上出现过,如果出现过跳过循环。
然后再判断其是否再树枝上出现过,如果没出现则可以继续递归(同时将其标记成在树枝上出现过)。
以下是代码:

class Solution {
    vector<vector<int>>result;
    vector<int>path;
public:
    void backtraving(vector<int> &nums, vector<bool>used) {
        if(path.size() == nums.size()) {
            result.push_back(path);
            return;
        }
        for(int i = 0; i < nums.size(); i++) {
            if(i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) continue;//在数层上出现过,则跳过当前循环
            if(used[i] == false) {//如果在当前数层上没出现过并且在树枝上也没出现过,则将其插入路径,标记成在树枝上出现过,然后递归回溯
                path.push_back(nums[i]);
                used[i] = true;
                backtraving(nums, used);
                used[i] = false;
                path.pop_back();
            }
        }
        return;
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<bool>used(nums.size(),false);//用布尔数组对每个数是否在树层和树枝上出现过做标记
        backtraving(nums, used);
        return result;
        
    }
};

总结

以上就是今天的内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值