代码随想录第28天|回溯算法

发布于:2024-06-23 ⋅ 阅读:(133) ⋅ 点赞:(0)

491. 非递减子序列

在这里插入图片描述
思路:

  • 不可以排序, 否则会改变元素的顺序
  • 对收获的结果有要求, num.size() >= 2, 且 num[i - 1] < num[i]
  • 需要进行去重, 不能使用排序后的方法去重
  • 每一层可用 unordered_set 去重
  • 组合问题, for 遍历需要标记起始位置

bug:

  • 一定要先判断元素是否重复, 再将元素插入
    请添加图片描述
//正确步骤
if (used.find(nums[i]) != used.end()) {
    continue;
} else if (res_tem.empty()) { // 重复元素
    res_tem.push_back(nums[i]);
} else if (res_tem.back() > nums[i]) { // 非递增
    continue;
} else {
    res_tem.push_back(nums[i]);
}

//错误步骤
//当res_tem为空时, 会将重复元素也添加, 一定需要先判断元素是否有使用
if (res_tem.size() == 0) { 
    res_tem.push_back(nums[i]);
} else if (used.find(nums[i]) != used.end()) { //重复元素
    continue;
} else if (!(res_tem.back() <= nums[i])) {  //非递增
    continue;
} else {
    res_tem.push_back(nums[i]);
}
class Solution {
public:
    vector<vector<int>> res;
    vector<int> res_tem;
    void myoperator(vector<int>& nums, int index) {
        if (res_tem.size() >= 2) {
            res.push_back(res_tem);
        }
        unordered_set<int> used;
        for (int i = index; i < nums.size(); i++) {
            
            if (used.find(nums[i]) != used.end()) {
                continue;
            } else if (res_tem.empty()) { // 重复元素
                res_tem.push_back(nums[i]);
            } else if (res_tem.back() > nums[i]) { // 非递增
                continue;
            } else {
                res_tem.push_back(nums[i]);
            }
			// 等效操作
            // if (!res_tem.empty() && nums[i] < res_tem.back()) {
            //     continue;
            // }
            // if (used.find(nums[i]) != used.end()) {
            //     continue;
            // }
            // res_tem.push_back(nums[i]);

            used.insert(nums[i]);
            myoperator(nums, i + 1);
            res_tem.pop_back();
        }
    }
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        myoperator(nums, 0);
        return res;
    }
};

46.全排列

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
在这里插入图片描述
思路:

  • 不能使用index来跳过元素, 因为与顺序有关, 所以遍历从 i = 0 开始
  • 每个元素都要遍历, 可以使用 used 数组去重
  • 无法用 unordered_set 去重, 每层树枝都有相互关联, 不是去除重复数字操作

请添加图片描述

class Solution {
public:
    vector<vector<int>> res;
    vector<int> res_tem;
    vector<bool> uesed;
    void myoperator(vector<int>& nums) {
        if (res_tem.size() == nums.size()) {
            res.push_back(res_tem);
            return;
        }
        for (int i = 0; i < nums.size(); i++) {
            if (uesed[i] == true) {
                continue;
            }
            uesed[i] = true;
            res_tem.push_back(nums[i]);
            myoperator(nums);
            uesed[i] = false;
            res_tem.pop_back();
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        uesed = vector<bool>(nums.size(), 0);
        myoperator(nums);
        return res;
    }
};

47. 全排列 II

给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列
在这里插入图片描述
请添加图片描述
思路:

  • 取叶子节点, 中间需要去除, 相同数层之间不能用同样的数值
  • 排列则需要从0开始, 使用used标记使用过的元素
class Solution {
public:
    vector<vector<int>> res;
    vector<int> res_tem;
    vector<bool> flag;
    void myoperator(vector<int>& nums) {
        if (res_tem.size() == nums.size()) {
            res.push_back(res_tem);
            return;
        }
        unordered_set<int> used;
        for (int i = 0; i < nums.size(); i++) {
            if (used.find(nums[i]) != used.end()) {
                continue;
            }
            if (flag[i] == true) {
                continue;
            }
            flag[i] = true;
            used.insert(nums[i]);
            res_tem.push_back(nums[i]);
            myoperator(nums);
            flag[i] = false;
            res_tem.pop_back();
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        flag = vector<bool>(nums.size(), false);
        myoperator(nums);
        return res;
    }
};

51. N 皇后
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
在这里插入图片描述
参考
请添加图片描述


37. 解数独
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
参考
请添加图片描述


网站公告

今日签到

点亮在社区的每一天
去签到