【算法】dfs



快乐的流畅:个人主页


个人专栏:《算法神殿》《数据结构世界》《进击的C++》

远方有一堆篝火,在为久候之人燃烧!

文章目录

  • 引言
  • 一、全排列
    • 1. 决策树
    • 2. 设计代码
      • 1. 全局变量
      • 2. dfs函数
      • 3. 细节问题
  • 二、子集
    • 解法一
    • 1. 决策树
    • 2. 设计代码
      • 1. 全局变量
      • 2. dfs函数
      • 3. 细节问题
    • 解法二
    • 1. 决策树
    • 2. 设计代码
      • 1. 全局变量
      • 2. dfs函数
      • 3. 细节问题
  • 三、子集的异或总和之和
  • 四、全排列 ||
  • 五、电话号码的字母组合
  • 六、括号生成
  • 七、组合
  • 八、目标和
  • 九、组合总和
  • 十、字母大小写全排列
  • 十一、优美的排列
  • 总结

引言

在实际的dfs问题中,大多时候并不会直接告诉你,而是需要自己发现可以使用dfs来解决。而是否能用dfs解决的关键,就是画出决策树!同时,不同的决策树代表不同的解决方式,对于同一问题,好的决策树往往能节省时间,提高效率。

一、全排列

1. 决策树


绿色部分,就是剪枝,因为全排列不能重复枚举。

2. 设计代码

1. 全局变量

  • vector<vector< int >> ret:用来保存最终所有的结果
  • vector< int > path:用来保存单一路径的结果
  • bool check[6]:用来实现剪枝

2. dfs函数

  • 将数组中所有数枚举一遍,如果没有枚举过,则将其加入path

3. 细节问题

  • 回溯
    • 清除path中最后一个数
    • 更改check中的标记
  • 剪枝:根据check的标记,去除重复枚举的情况
  • 递归出口:当path路径长度等于枚举数组长度,则将其加入ret,返回
class Solution
{vector<vector<int>> ret;vector<int> path;bool check[6];//实现剪枝
public:void dfs(vector<int>& nums){if(path.size() == nums.size()){ret.push_back(path);return;}for(int i=0; i<nums.size(); ++i){if(!check[i])//剪枝{path.push_back(nums[i]);check[i] = true;dfs(nums);//回溯 - 恢复现场path.pop_back();check[i] = false;}}}vector<vector<int>> permute(vector<int>& nums){dfs(nums);return ret;}
};

二、子集

解法一

1. 决策树

2. 设计代码

1. 全局变量

  • vector<vector< int >> ret:用来保存最终所有的结果
  • vector< int > path:用来保存单一路径的结果

2. dfs函数

  • 对于数组中的每一个数,都遵循选或不选两种方式
    • 不选:直接dfs下一层
    • 选:先将其加入path,再dfs下一层
  • dfs(nums, i):增加参数i作为当前数的下标

3. 细节问题

  • 回溯:删除path中最后一个数
  • 递归出口:当i枚举完所有数,来到数组末尾,则将path加入ret,返回
class Solution
{vector<vector<int>> ret;vector<int> path;
public:void dfs(vector<int>& nums, int i){if(i == nums.size()){ret.push_back(path);return;}//不选dfs(nums, i+1);//选path.push_back(nums[i]);dfs(nums, i+1);path.pop_back();}vector<vector<int>> subsets(vector<int>& nums){dfs(nums, 0);return ret;}
};

解法二

1. 决策树


由于决策树不同的选取,解法二要优于解法一

2. 设计代码

1. 全局变量

  • vector<vector< int >> ret:用来保存最终所有的结果
  • vector< int > path:用来保存单一路径的结果

2. dfs函数

  • 按照集合中元素的个数进行分类
  • 依据集合的互异性,每层dfs只能选取下标i后面的数
  • dfs(nums, i):增加参数i作为当前数的下标

3. 细节问题

  • 回溯:删除path中最后一个数
  • 递归出口:每一层path都是结果,都需要添加到ret
class Solution
{vector<vector<int>> ret;vector<int> path;
public:void dfs(vector<int>& nums, int i){ret.push_back(path);for(int j=i; j<nums.size(); ++j){path.push_back(nums[j]);dfs(nums, j+1);path.pop_back();}}vector<vector<int>> subsets(vector<int>& nums){dfs(nums, 0);return ret;}
};

三、子集的异或总和之和


思路:子集的变式题(按照集合元素个数分类)

class Solution
{int ret = 0;int path = 0;
public:void dfs(vector<int>& nums, int pos){ret += path;for(int i=pos; i<nums.size(); ++i){path ^= nums[i];dfs(nums, i + 1);path ^= nums[i];}}int subsetXORSum(vector<int>& nums){dfs(nums, 0);return ret;}
};

四、全排列 ||


思路:本题是全排列的进阶版,存在重复元素,所以剪枝是关键。

  • 前提:先对数组排序
  • 同一个元素只能使用一次(check)
  • 对于每一个节点,相同的元素只能选一次
class Solution
{vector<vector<int>> ret;vector<int> path;bool check[8];
public:void dfs(vector<int>& nums){if(path.size() == nums.size()){ret.push_back(path);return;}for(int i=0; i<nums.size(); ++i){if(!check[i] && (i == 0 || nums[i] != nums[i-1] || check[i-1])){path.push_back(nums[i]);check[i] = true;dfs(nums);check[i] = false;path.pop_back();}}}vector<vector<int>> permuteUnique(vector<int>& nums){sort(nums.begin(), nums.end());dfs(nums);return ret;}
};

五、电话号码的字母组合


细节:用哈希表存储数字与字符串的映射关系

class Solution
{vector<string> ret;string path;vector<string> hash = {"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
public:void dfs(string& digits, int pos){if(path.size() == digits.size()){ret.push_back(path);return;}int n = digits[pos] - '0';string s = hash[n];for(int i=0; i<s.size(); ++i){path.push_back(s[i]);dfs(digits, pos + 1);path.pop_back();}}vector<string> letterCombinations(string& digits){if(digits.size() == 0) return ret;dfs(digits, 0);return ret;}
};

六、括号生成



class Solution
{vector<string> ret;string path;int n;
public:void dfs(int left, int right){if(right == n){ret.push_back(path);return;}if(left < n){path.push_back('(');dfs(left + 1, right);path.pop_back();}if(right < left){path.push_back(')');dfs(left, right + 1);path.pop_back();}}vector<string> generateParenthesis(int _n){n = _n;dfs(0, 0);return ret;}
};

七、组合


class Solution
{vector<vector<int>> ret;vector<int> path;int n, k;
public:void dfs(int pos){if(path.size() == k){ret.push_back(path);return;}for(int i=pos; i<=n; ++i){path.push_back(i);dfs(i + 1);path.pop_back();}}vector<vector<int>> combine(int _n, int _k){n = _n, k = _k;dfs(1);return ret;}
};

八、目标和


class Solution
{int ret = 0;int t;
public:void dfs(vector<int>& nums, int pos, int path){if(pos == nums.size()){if(path == t) ++ret;return;}dfs(nums, pos + 1, path + nums[pos]);dfs(nums, pos + 1, path - nums[pos]);}int findTargetSumWays(vector<int>& nums, int target){t = target;dfs(nums, 0, 0);return ret;}
};

九、组合总和


class Solution
{vector<vector<int>> ret;vector<int> path;int t;
public:void dfs(vector<int>& candidates, int pos, int sum){if(sum >= t){if(sum == t) ret.push_back(path);return;}for(int i=pos; i<candidates.size(); ++i){path.push_back(candidates[i]);dfs(candidates, i, sum + candidates[i]);path.pop_back();}}vector<vector<int>> combinationSum(vector<int>& candidates, int target){t = target;dfs(candidates, 0, 0);return ret;}
};

十、字母大小写全排列


class Solution
{vector<string> ret;
public:void dfs(string& s, int pos, string path){if(path.size() == s.size()){ret.push_back(path);return;}if(isalpha(s[pos])){dfs(s, pos + 1, path + (char)tolower(s[pos]));dfs(s, pos + 1, path + (char)toupper(s[pos]));}else dfs(s, pos + 1, path + s[pos]);}vector<string> letterCasePermutation(string& s){dfs(s, 0, "");return ret;}
};

十一、优美的排列


class Solution
{int ret = 0;bool check[20];int n;
public:void dfs(int pos, int path){if(path == n){++ret;return;}for(int i=1; i<=n; ++i){if(!check[i] && (i % pos == 0 || pos % i == 0)){check[i] = true;dfs(pos + 1, path + 1);check[i] = false;}}}int countArrangement(int _n){n = _n;dfs(1, 0);return ret;}
};

总结

  • 决策树
  • 设计代码
    • 全局变量
    • dfs函数
    • 细节问题
      • 回溯
      • 剪枝
      • 递归出口

真诚点赞,手有余香

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/11223.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PCB的盘中孔

目录 一、什么时候可以在焊盘上打孔&#xff1f; 二、什么时候可以在焊盘上打孔&#xff1f; 绘制PCB时经常会遇到空间不够无法走线&#xff0c;这时我们会放置过孔使信号线穿过电路板一侧到达另一侧进行走线&#xff0c;这样既方便走线&#xff0c;也能够节省板子空间。有时…

Linux提权--第三方软件MYSQL数据库提权(WEB+本地)

免责声明:本文仅做技术交流与学习,非法搞事后果自负... 目录 靶场镜像: 过程: 手工: 下载mysql udf poc 进行编译. 进入数据库进行UDF导出 下载(上传) 创建do_system函数调用 探针(./LinEnum.sh),查找suid权限. 配合使用find调用执行 工具: 过程: 外连不上? 隧道出…

气膜建筑电源配置是怎样的—轻空间

在气膜建筑中&#xff0c;电源配置是确保建筑控制系统连续运行的重要组成部分。以下是该建筑的电源配置方案&#xff1a; 1. 市电供电与备用发电机&#xff1a; 为了应对市电中断等突发情况&#xff0c;系统采用市电供电与备用柴油发电机双重供电方式。这种配置保证了即使在市电…

UV胶的应用场景有哪些?

UV胶是一种特殊的胶水&#xff0c;其固化过程需要紫外光照射。它具有快速固化、高强度、无溶剂挥发等优点&#xff0c;因此在许多应用场景中被广泛使用。UV胶的应用场景非常广泛&#xff0c;包括但不限于以下几个方面&#xff1a; 1.电子产品组装: UV胶在电子产品的组装中扮演…

高校课程评价|基于SSM+vue的高校课程评价系统的设计与实现(源码+数据库+文档)

高校课程评价系统 目录 基于SSM&#xff0b;vue的高校课程评价系统的设计与实现 一、前言 二、系统设计 三、系统功能设计 1管理员功能模块 2学生功能 3教师功能 4专家功能 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&…

企业微信hook接口协议,ipad协议http,格式化发送@消息

格式化发送消息 参数名必选类型说明uuid是String每个实例的唯一标识&#xff0c;根据uuid操作具体企业微信send_userid是long要发送的人或群idisRoom是bool是否是群消息 请求示例 {"uuid":"1688853790599424","send_userid":1069605295501613…

实验0.0 Visual Studio 2022安装指南

Visual Studio 2022 是一个功能强大的开发工具&#xff0c;对于计算机专业的学生来说&#xff0c;它不仅可以帮助你完成学业项目&#xff0c;还能为你将来的职业生涯打下坚实的基础。通过学习和使用 Visual Studio&#xff0c;你将能够更高效地开发软件&#xff0c;并在编程领域…

电力乙级资质延伸换证的政策背景与趋势

电力乙级资质延伸换证的政策背景与趋势主要体现在以下几个方面&#xff1a; 一、政策背景 行业发展需求&#xff1a;随着电力行业的不断发展和市场竞争的加剧&#xff0c;电力设计和施工企业需要不断提升自身的技术水平和业务能力&#xff0c;以适应市场的变化和满足客户的需求…

Alibaba SpringCloud集成Nacos、openFeign实现负载均衡-15

Spring cloud alibaba Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件&#xff0c;方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。 主要功能 服务限流降级&#xff1a;默认支持 WebS…

Unity生命周期函数详解

Unity生命周期函数详解 Unity生命周期函数是Unity引擎中用于控制游戏对象行为的一系列方法。它们在游戏的不同阶段被自动调用&#xff0c;允许开发者在适当的时机执行特定的代码。了解和正确使用生命周期函数对于创建流畅和高效的游戏至关重要。 生命周期函数概述 Unity生命…

Nacos集群的扩展性和容错性如何?

Nacos集群的扩展性与容错性深度解析 在微服务的架构设计中&#xff0c;服务注册与发现、配置管理是两个至关重要的环节。它们如同微服务架构的“中枢神经”&#xff0c;负责着服务的协调与调度。而Nacos&#xff0c;作为一款优秀的服务注册与发现、配置管理平台&#xff0c;凭…

Leetcode 3147. Taking Maximum Energy From the Mystic Dungeon

Leetcode 3147. Taking Maximum Energy From the Mystic Dungeon 1. 解题思路2. 代码实现 题目链接&#xff1a;3147. Taking Maximum Energy From the Mystic Dungeon 1. 解题思路 这一题的话我们倒序看一下以各个位置作为终点时前面各个位置作为起点时的energy各是多少&am…

外网如何访问内网服务器?快解析内网穿透使用教程

随着信息化建设的飞速发展&#xff0c;为了提高工作效率&#xff0c;越来越多的企业搭建了ERP、OA、CRM等应用服务器&#xff0c;同时为了数据安全考虑&#xff0c;将应用服务器放在内网。随着企业的发展壮大&#xff0c;访问需求不再局限于局域网&#xff0c;如何实现外网访问…

(13)配置飞行中的FFT(二)

文章目录 前言 1 FFT 动态谐波陷波频率跟踪 2 FFT 选项 2.1 后置滤波器链 FFT 分析窗口 2.2 电机噪音检查 3 典型用途 4 补充信息 5 参数说明 前言 FFT 模式跟踪将基频设置为最大的噪声峰值。 1 FFT 动态谐波陷波频率跟踪 FFT 模式跟踪将基频设置为最大的噪声峰值。通…

leetcode经典例题之使用栈实现队列

P. S.&#xff1a;以下代码均在VS2019环境下测试&#xff0c;不代表所有编译器均可通过。 P. S.&#xff1a;测试代码均未展示头文件stdio.h的声明&#xff0c;使用时请自行添加。 目录 1、题目展示2、题目分析3、完整代码演示4、结语 1、题目展示 前面我们了解过如何实现栈相…

[力扣题解]406. 根据身高重建队列

题目&#xff1a;406. 根据身高重建队列 思路 贪心法&#xff1b; 本题涉及到2种选择因素&#xff1a;h和k&#xff1b; 优先考虑h&#xff0c;再考虑k&#xff1b; 如果在你的脑子里&#xff0c;这2个变量搅在一起就完蛋了 w(&#xff9f;Д&#xff9f;)w 代码 // 有2种因…

搭建nacos集群

1.修改nacos/conf/application.properties 2.在数据库中执行nacos/conf/nacos-mysql.sql脚本 3.修改nacos/conf/cluster.conf文件 4.修改startup.sh文件模式为集群 5.启动服务 附&#xff1a;安装nginx 修改/usr/local/openresty/nginx/conf/nginx.confi文件 http{}中增加如下…

电机控制系列模块解析(20)—— MTPA

一、MTPA MTPA 是 "Maximum Torque Per Ampere" 的缩写&#xff0c;意为“最大转矩电流比”。在电机控制系统中&#xff0c;特别是永磁同步电机&#xff08;PMSM&#xff09;或其它永磁电机的控制策略中&#xff0c;MTPA 控制旨在实现电机在给定负载条件下&#xff…

uniapp 生成安卓证书没有md5指纹怎么办?

由于最新的jdk版本对应的keystore工具无法查看到md5指纹信息 但是不代表它没有md5指纹信息&#xff0c;只是看不到而已 解决方案&#xff1a; 登录uniapp开发者后台生成安卓云端证书

【前端开发】Uniapp:uView组件库和封装接口请求

【uView组件库导入及使用】 1. 导入uView组件库依赖 &#xff08;无package.json&#xff09;npm init -ynpm install uview-ui1.8.8安装成功&#xff0c;自动放到“/node_modules/uview-ui/”&#xff08;可自行更换路径&#xff09; 2. 项目配置使用uView App.vue <style…