【算法】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;并在编程领域…

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

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

Unity生命周期函数详解

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

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

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

搭建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开发者后台生成安卓云端证书

获取Linux上的Redis的用户名、密码、端口、host等信息

目录 进入redis-cli的目录 启动./redis-cli服务 查询密码 查询用户名 查询端口 查询host 参考文章&#xff1a;解决redis-cli连接时出现Could not connect to Redis at 127.0.0.1:6379: Connection refused-阿里云开发者社区 (aliyun.com) linux查看redis用户和密码_mo…

ChatGPT付费创作系统软件开发

uni-app框架&#xff1a;使用Vue.js开发跨平台应用的前端框架&#xff0c;编写一套代码&#xff0c;可编译到Android、小程序等平台。 框架支持:springboot/Ssm/thinkphp/django/flask/express均支持 前端开发:vue.js 可选语言&#xff1a;pythonjavanode.jsphp均支持 运行软件…

【Spring Boot】Spring Boot 中的 Starter

Spring Boot 中的 Starter 1.常用 Starter2.为什么要用 Starter3.Starter 有哪些要素 我们都知道&#xff0c;Spring 的功能非常强大&#xff0c;但也有些弊端。比如&#xff1a;我们需要手动去配置大量的参数&#xff0c;没有默认值&#xff0c;需要我们管理大量的 jar 包和它…

【JS面试题】闭包

一、自由变量 在学习闭包之前&#xff0c;首先了解一下什么是自由变量&#xff1a; 一个变量在当前作用域&#xff08;比如函数内&#xff09;没有定义&#xff0c;但是被使用了&#xff0c;这个变量就是自由变量。在定义该函数的位置&#xff0c;向上级作用域&#xff0c;一…

【C++】STL — map和set的使用详细介绍

前言 本章将继续学习STL中的两个很重要的容器map和set&#xff0c;其底层实现是封装了一个红黑树&#xff0c;我们通过本节来学习和深入了解一下这两大容器。。。 序列式容器&#xff1a; string 、Vector、List 、dequeue 关联式容器&#xff1a;MAP 、SET、nordered_map、uno…

MySql软件安装

1.打开mysql官网网址 MySQL :: Download MySQL Community Server 2.本次针对版本8的图形化界面安装&#xff0c;下载成功后接下来对MySQL进行安装 3.图形化下载后有一个MSI文件 4.我们安装典型即可&#xff0c;选择第一个 5.选择数据库信息存放的路径&#xff0c;我默认放在C盘…

如何解决pycharm在HTML文件中注释快捷键出错的问题(HTML注释规则出错)

文章目录 💢 问题 💢🏡 演示环境 🏡💯 解决方案 💯⚓️ 相关链接 ⚓️💢 问题 💢 你是否在编程时遇到过这样的烦恼?当你正专注地编写HTML代码,想要快速注释掉某部分内容时,却发现PyCharm的注释快捷键失灵了(没有使用正确的注释格式)。这不仅打断了你的工作…