刷题笔记Day25回溯算法part04

刷题笔记Day25:回溯算法part04

题目:非递减子序列

491. 非递减子序列
给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。

数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。

示例 1:

输入:nums = [4,6,7,7]
输出:[[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]

思路:因为本体不能用sortnums数组中的值进行变化,因此需要使用set来对同一层的树状结构进行一个去重,例如在[4,6,7,7,4]的逻辑中若是在同一层的递归中使用了7则后面所有子集开头为7的所有组合都被第一个7所包括了例如[7][7,7]这两个在7,7,4这里若没有这个去重逻辑会被重复两次,代码如下:

class Solution {
public:
    bool isavailable(vector<int>& nums)
    {
        if(nums.size() == 1)
        {
            return false;
        }
        for(int i = 1; i<nums.size();i++)
        {
            if(nums[i-1] > nums[i])
            {
                return false;
            }
        }
        return true;
    }
    vector<int> tmp;
    vector<vector<int>> result;
    void backtracking(vector<int>& nums, int start_index)
    {
        if(nums.size() == start_index)
        {
            return;
        }
        unordered_set<int> used;
        for(int i = start_index;i < nums.size();i++)
        {
            if(i>start_index && used.find(nums[i]) != used.end())
            {
                continue;
            }
            tmp.push_back(nums[i]);
            used.insert(nums[i]);
            if(isavailable(tmp))
            {
                result.push_back(tmp);
            }
            backtracking(nums,i+1);
            tmp.pop_back();
        }
    }
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        backtracking(nums,0);
        return result;
    }
};

题目:全排列

46. 全排列

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

示例 1:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

思路:若将上面的递归过程想象成一个树状图,那么今天的第一题是从横向来防止数字的重复,而本体是从递归方向即纵向来防止数字的重复使用,因此需要将set的位置放置在全局中,其他部分和上一题相同,完整代码如下:

class Solution {
public:
    vector<int> tmp;
    vector<vector<int>> result;
    set<int> uset;
    void backtracking(vector<int>& nums)
    {
        if(tmp.size() == nums.size())
        {
            result.push_back(tmp);
        }

        for(int i = 0;i < nums.size();i++)
        {
            if(uset.find(nums[i]) == uset.end())
            {
                tmp.push_back(nums[i]);
                uset.insert(nums[i]);
                backtracking(nums);
                tmp.pop_back();
                uset.erase(nums[i]);
            }
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        backtracking(nums);
        return result;
    }
};

题目:全排列 II

47. 全排列 II

给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。

示例 1:

输入:nums = [1,1,2]
输出:
[[1,1,2],
 [1,2,1],
 [2,1,1]]

思路:本体需要从纵向和横向同时去重,我在纵向即递归方向上采用的是使用一个数组,在递归中将数组中使用过的元素进行标记;而横向去重,即同一层递归中的for循环中,使用的是set,只要使用过的数据都会将其其塞入set中,并在同层循环中的每一个开始就判断是有相同的数据已经被使用,若之前使用过说明一这一子集的所有可能组合都被包含了无需再次讨论,具体代码如下,其中横向去重使用的是uset而纵向去重使用的是used

#include <vector>
class Solution {
public:
    vector<int> tmp;
    vector<vector<int>> result;
    vector<int>used;
    void backtracking(vector<int>& nums)
    {
        if(tmp.size() == nums.size())
        {
            result.push_back(tmp);
            return;
        }
        set<int> uset;
        for(int i = 0 ; i<nums.size();i++)
        {
            if(uset.find(nums[i]) != uset.end() ||used[i] == 1)
            {
                continue;
            }
            tmp.push_back(nums[i]);
            uset.insert(nums[i]);
            used[i] =1;
            backtracking(nums);
            tmp.pop_back();
            used[i] = 0;
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        for(int i = 0; i<nums.size();i++)
        {
            used.push_back(0);
        }
        backtracking(nums);
        return result;
    }
};
posted @ 2025-04-21 19:11  涛Tao  阅读(167)  评论(0)    收藏  举报