【递归、搜索与回溯】专题三 穷举vs暴搜vs回溯vs剪枝

文章目录

  • 1.全排列
    • [1.1 题目](#1.1 题目)
    • [1.2 思路](#1.2 思路)
    • [1.3 代码](#1.3 代码)
  • 2.子集
    • [2.1 题目](#2.1 题目)
    • [2.2 思路](#2.2 思路)
    • [2.3 代码](#2.3 代码)

1.全排列

1.1 题目

题目链接

1.2 思路

1.3 代码

cpp 复制代码
class Solution {
public:
    vector<vector<int>> ret;//最终结果变量
    vector<int> path;//单次搜索
    bool check[7];//判断路径上的元素是否已经选择过
    vector<vector<int>> permute(vector<int>& nums) {
        dfs(nums);
        return ret;
    }

    void dfs(vector<int>& nums)
    {
    	//如果所有元素都选择过了,就返回,定义函数递归出口
        if(nums.size() == path.size())
        {
            ret.push_back(path);//把此次结果加入到最终结果中
            return;
        }

		//循环遍历nums中的每个元素
        for(int i = 0; i < nums.size(); i++)
        {
            if(check[i] == false)//这个数还没加入到path
            {
                path.push_back(nums[i]);//把这个数加入到path
                check[i] = true;//把check坐上true标记,表示已加入到path
                dfs(nums);//进行深度优先遍历
                //dfs完了之后,就相当于进入决策树的下一个分支了
                //回溯 -> 恢复现场
                path.pop_back();
                check[i] = false;
            }
        }
    }
};

2.子集

2.1 题目

题目链接

2.2 思路


2.3 代码

方法一

cpp 复制代码
//方法一 灵神代码
//这段代码实现了一个经典的算法问题:给定一个整数数组 nums,返回其所有可能的子集(幂集)。
//幂集是指一个集合的所有子集组成的集合,包括空集和集合本身。
//代码使用了深度优先搜索(DFS)的方法来生成所有子集。
class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> ret;//存储返回结果:最终生成的所有子集
        vector<int> path;//在递归过程中记录当前正在构建的子集
        int n = nums.size();//nums数组的大小
        //n:递归过程中用于判断是否已经处理完数组中的所有元素
        
        //定义了一个递归函数 dfs,用于深度优先搜索生成所有子集。
        //auto 表示函数的返回类型会自动推导,这里返回类型为 void。
        //this auto&& dfs 是一个 C++17 的特性,表示 dfs 是一个可调用对象(可以是函数、lambda 表达式等),并且支持递归调用自身。
        //int i 是递归函数的参数,表示当前处理到数组 nums 的第 i 个元素。
        auto dfs = [&](this auto&& dfs, int i) -> void {
        	//递归的终止条件
            if (i == n) { // 子集构造完毕
                ret.emplace_back(path);
                return;
            }

            // 选nums[i]
            path.push_back(nums[i]);
            dfs(i + 1);
            path.pop_back(); // 回溯到上一层,需要pop掉push的元素,恢复现场
            // 不选nums[i]
            dfs(i + 1); 
        };
        dfs(0);
        return ret;
    }
};
cpp 复制代码
//方法一 代码二 更好理解
class Solution {
public:
    vector<vector<int>> ret;
    vector<int> path;

    vector<vector<int>> subsets(vector<int>& nums) {
        dfs(nums, 0);
        return ret;
    }

    void dfs(vector<int>& nums, int pos)
    {
    	//递归结束条件
        if(pos == nums.size())
        {
            ret.push_back(path);
            return;
        }

        // 1.选nums[pos]
        path.push_back(nums[pos]);
        dfs(nums, pos + 1);
        path.pop_back();//回溯到上一层时,恢复现场,pop;

        //2.不选nums[pos]
       dfs(nums, pos + 1);
    }
};

方法二

cpp 复制代码
class Solution {
public:
    vector<vector<int>> ret;
    vector<int> path;

    vector<vector<int>> subsets(vector<int>& nums) {
        dfs(nums, 0);
        return ret;
    }

    void dfs(vector<int>& nums, int pos)
    {
        ret.push_back(path);//每次进入递归都要先push,每次进入递归都是一个结果
        for(int i = pos; i < nums.size(); i++)
        {
            path.push_back(nums[i]);//先加入当前元素
            dfs(nums, i + 1);//继续往下递归
            path.pop_back();//恢复现场
        }
    }
};
相关推荐
watersink7 小时前
机器学习随机森林
人工智能·随机森林·机器学习
乐观勇敢坚强的老彭7 小时前
C++ 竞赛常用算法模板速查表
开发语言·c++·算法
高洁017 小时前
工信部教考中心证书
人工智能·深度学习·算法·机器学习·知识图谱
SomeB1oody7 小时前
【RustyML入门】2.13. 孤立森林
开发语言·后端·机器学习·rust·教程
我变成萤火虫8 小时前
河南萌新联赛2026第(三)场:郑州轻工业大学
数据结构·c++·算法·贪心算法·stl·深度优先·哈希算法
Dr.kangder8 小时前
嵌入式面试总结(十九)——内存泄露
单片机·算法·面试·职场和发展·架构·硬件架构
Herbert_hwt8 小时前
【C语言基础】常量、选择结构与运算符全解析
c语言·开发语言·算法
buhuizhiyuci8 小时前
【Linux 篇】数字世界的水流蓄水池 —— IO 缓冲区机制深度实战解析
linux·运维·服务器·c++
liulilittle8 小时前
LLM 推理引擎与内核系统工程原理
c++·ai·llm·内存·memory·core·kernel
Suxing98 小时前
C语言基础分享:从“租房”到“拆迁”,C语言动态内存管理
java·数据结构·算法