代码随想录算法训练营第29天 | 回溯算法part05:● 491.递增子序列 ● 46.全排列 ● 47.全排列 II

#491 递增子序列  有点难  30min 找不到合适的去重逻辑了,于是没办法用了set> 通过了

“90子集ii 中我们是通过排序,再加一个标记数组来达到去重的目的。 而本题求自增子序列,是不能对原数组进行排序的,排完序的数组都是自增子序列了。 所以不能使用之前的去重逻辑!”

用[4, 7, 6, 7] 或者 [4,6,7,5,7] 都能体现这个题的特点,正确的逻辑是:同一父节点下的同层上使用过的元素就不能再使用了

然后本来想用 unordered_set>发现不行,还要自定hash func,但换成set就行了 

代码随想录算法训练营第29天 | 回溯算法part05:● 491.递增子序列 ● 46.全排列 ● 47.全排列 II_第1张图片

代码随想录算法训练营第29天 | 回溯算法part05:● 491.递增子序列 ● 46.全排列 ● 47.全排列 II_第2张图片

代码随想录算法训练营第29天 | 回溯算法part05:● 491.递增子序列 ● 46.全排列 ● 47.全排列 II_第3张图片

 我的code:用set的,comment掉的是走不通的去重逻辑

    set> res;
    vector vec;

    void backtrack(int startIdx, vector& nums){
        if(startIdx>=nums.size()) return;
        
        for(int i=startIdx; i=2) res.insert(vec);
            backtrack(i+1,nums);
            vec.pop_back();
        }
    }

    vector> findSubsequences(vector& nums) {
        res.clear();
        vec.clear();
        backtrack(0,nums);
        vector> result(res.begin(), res.end());
        return result;
    }

根据随想录修改过后的:其实就是加了个unordered_set uset;(每层都有一个自己的新的),同一父节点下的同层上使用过的元素就不能再使用了。 

学到了vec最后一个元素可以直接用.back()

    set> res;
    vector vec;

    void backtrack(int startIdx, vector& nums){
        if(startIdx>=nums.size()) return;

        unordered_set uset; // 使用set来对本层元素进行去重
        for(int i=startIdx; i=2) res.insert(vec);
            backtrack(i+1,nums);
            vec.pop_back();
        }
    }

    vector> findSubsequences(vector& nums) {
        res.clear();
        vec.clear();
        backtrack(0,nums);
        vector> result(res.begin(), res.end());
        return result;
    }

代码随想录算法训练营第29天 | 回溯算法part05:● 491.递增子序列 ● 46.全排列 ● 47.全排列 II_第4张图片

#46 全排列 25min, 主要就是去重

弄了一个set去重,但是一开始没写对,在push 到 res那里就直接clear了,结果WA,一个个print出来发现不对,set也应该加入回溯

一个个print debug真的有点慢的,尤其是写print还不熟练的时候,比如print set:用for auto ele:set 就行

    vector> res;
    vector vec;
    set used;

    void backtrack(vector& nums){
        if(vec.size()==nums.size()){
            res.push_back(vec);
            return;
        }

        for(int i=0;i> permute(vector& nums) {
        backtrack(nums);
        return res;
    }

啊其实改了一下发现很容易,没什么怕错的:然后我的set当做 global var因为我有点怕放在传参数那里会传错,但是还是要练一下再写一版。然后随想录和我的区别就是不用的set,用的是

vector used(nums.size(), false);
    vector> res;
    vector vec;
    

    void backtrack(vector& nums, set used){
        if(vec.size()==nums.size()){
            res.push_back(vec);
            return;
        }

        for(int i=0;i> permute(vector& nums) {
        set used;
        backtrack(nums,used);
        return res;
    }

代码随想录算法训练营第29天 | 回溯算法part05:● 491.递增子序列 ● 46.全排列 ● 47.全排列 II_第5张图片

 下面也放一下随想录的46代码,这样47题看总结时可以参考

    vector> result;
    vector path;
    void backtracking (vector& nums, vector& used) {
        // 此时说明找到了一组
        if (path.size() == nums.size()) {
            result.push_back(path);
            return;
        }
        for (int i = 0; i < nums.size(); i++) {
            if (used[i] == true) continue; // path里已经收录的元素,直接跳过
            used[i] = true;
            path.push_back(nums[i]);
            backtracking(nums, used);
            path.pop_back();
            used[i] = false;
        }
    }
    vector> permute(vector& nums) {
        result.clear();
        path.clear();
        vector used(nums.size(), false);
        backtracking(nums, used);
        return result;
    }

时间复杂度不用看代码,直接想做排列就是n! 

#47

先是把#46的set里放value改成set里放index,这里注意一点是,#46有两种实现方法,我的是放到set里,随想录是弄一个bool表。我这种放到set里面,必须要把原来放value改成放index,不然不行。但他那种弄bool表的,只需要把原来这一句不要再写就行

 if (used[i] == true) continue; // path里已经收录的元素,直接跳过

然后准备去重,一时没想到去重逻辑,偷个懒,先用set of vec做一下,过了:

    set> res;
    vector vec;
    
    void backtrack(vector& nums, set used){
        if(vec.size()==nums.size()){
            res.insert(vec);
            return;
        }

        for(int i=0;i> permuteUnique(vector& nums) {
        set used;
        backtrack(nums,used);
        vector> result(res.begin(),res.end());
        return result;
    }

好,现在来讲正经去重逻辑,本题是 40.组合总和II 去重逻辑 和 46.全排列 的结合

重中之重是这句:if (i > 0 && nums[i] == nums[i - 1] && used.find(i-1)!=used.end()) continue;

排序后,前后相等的元素,而且前一个用过了,就不会让再来一次了

举个例子:

idx [0, 1, 2 ]   [1, 0, 2 ]

val [1, 1, 2 ]   [1, 1, 2 ]

就这两个东西不应该都出现的,这句就能保证

    vector> res;
    vector vec;
    

    void backtrack(vector& nums, set used){
        if(vec.size()==nums.size()){
            res.push_back(vec);
            return;
        }

        for(int i=0;i 0 && nums[i] == nums[i - 1] && used.find(i-1)!=used.end()) continue;
            
            vec.push_back(nums[i]);
            used.insert(i);
            backtrack(nums,used);
            vec.pop_back();
            used.erase(i);
        }
    }

    vector> permuteUnique(vector& nums) {
        sort(nums.begin(),nums.end());
        set used;
        backtrack(nums,used);
        return res;
    }

你可能感兴趣的:(代码随想录一刷,算法,数据结构,c++)