1.深度优先搜索中的关键

2.深度优先搜索小结

3.深度优先搜索和回溯法的区别

4.深度优先搜索与递归的区别


1.深度优先搜索中的关键

深度搜索算法通常用来 解决 全排列不重复组合分组问题多条路径路径的条数等等

对于深度优先搜索,最重要的参数有两个,第一是 深度搜索的次数 step,可以看做需要将待搜索的结果放入到 step 个盒子中,直到放满为止。

第二个是每一次 深度搜索的开始位置start, 主要控制的是每次深度搜索的范围

比如:

对于全排列问题,求[1,2,3]的全排列问题,此时我们可以将问题转化为 将 1,2,3按不同的次序放入到三个盒子中,我们需要的是控制深度搜索的次数step,这个次数就是我们深度搜索的结束条件(收敛条件)

对于求子集问题,求[1,2,3]的全部子集(不能重复),与全排列不同,为了求出不重复的子集,我们需要使在1右边的元素永远在1的右边,也就是说,在第二次深度搜索时我们的搜索范围应该是[2,3],此时我们并不控制深度搜索的次数,而是控制的是深度搜索开始的位置。

class Solution {
public:vector<vector<int>> permute(vector<int>& nums) {vector<bool> book(nums.size(),false);vector<int> tmp;vector<vector<int>> res;dfs(nums,0,book,tmp,res);return res;}private:void dfs(vector<int>& nums,int step,vector<bool>&book,vector<int>& tmp,vector<vector<int>>& res){if(step == nums.size()){res.push_back(tmp);return;}for(int i = 0; i < nums.size();i++){if(!book[i]){tmp.push_back(nums[i]);book[i] = true;dfs(nums,step+1,book,tmp,res);tmp.pop_back();book[i] = false;}}}
};

class Solution {
public:vector<vector<int>> subsets(vector<int>& nums) {vector<vector<int>> res;vector<int> path;dfs(nums, 0, path, res);return res;}
private:void dfs(vector<int>& nums, int start, vector<int>& path, vector<vector<int>>& res){res.push_back(path);for(int i = start; i < nums.size(); i++)//这里用的是start,控制每一次深搜的范围{path.push_back(nums[i]);dfs(nums,i+1,path,res);path.pop_back();}}};

当然,有些情况下,我们即需要控制 深搜的次数 又需要控制每一次深搜的范围,这种问题典型特征是 分配出了要求的盒子数,

而且是组合问题

较简单的:

class Solution {
public:vector<vector<int>> combine(int n, int k) {vector<vector<int>> res;vector<int> path;dfs(n, k,1, 0, path, res);return res;}private:void dfs(int n, int k,int start, int step, vector<int>& path, vector<vector<int>>& res){if(step == k){res.push_back(path);return;}for(int i = start; i <= n; i++){path.push_back(i);dfs(n,k,i+1,step+1,path,res);path.pop_back();}}
};

较难的:

这一题目中,虽然没有明确说拆分为的盒子数,但是根据IP的特征,应该拆分为4个盒子

同时,这也是一个组合问题(只不过是字符串写在了一起而已),需要控制每次深度搜索的初始位置

class Solution {
public:vector<string> restoreIpAddresses(string s) {vector<string> res;string path;if(s.size() > 12){return res;}dfs(s, 0,0,path,res);return res;}
private:void dfs(string s, int start,int step,string path, vector<string>& res){if(start == s.size() && step == 4){res.push_back(path);return;}for(int i = 1; i <= s.size();i++){if(start + i > s.size()){return;}string section = s.substr(start,i);if(section.size() > 1 && section[0] == '0' || convert(section) > 255){return;}//同时这里用了一个小技巧,因为是字符串,所以不能pop掉后面过来的字符串,所以选择下面这一种方式,来进行回溯dfs(s,start+i,step+1,step == 0 ? section : path + "." + section,res);}}int convert(string section){int sum = 0;for(int i = 0; i < section.size(); i++){sum = sum*10 + section[i] - '0';}return sum;}};

对于二维空间的深度搜索,如果起点已经定下,则由此点开始向上下左右扩展即可,如果起点没有定下来,则在主调函数中进行遍历起点,并对每一个起点进行深度优先搜素,同时,如果深度搜索函数有返回值,则对其进行组合处理即可

起点确定下的二维深度搜索:

class Solution {
public:int uniquePaths(int m, int n) {vector<vector<int>> book(m+1,vector<int>(n+1,0));return dfs(m,n,0,0,book);   }private:int dfs(int m, int n,int i,int j,vector<vector<int>>& book){if( i == m-1 && j == n-1)//收敛条件{return 1;}if(i >= m || j >= n){return 0;}return getbook(m,n,i+1,j,book) + getbook(m,n,i,j+1,book);        }int getbook(int m,int n,int i,int j,vector<vector<int>>& book){if(book[i][j] > 0){return book[i][j];}else{return book[i][j] = dfs(m,n,i,j,book);}}};

起点不确定条件下的二维深度搜索:

class Solution {
public:bool exist(vector<vector<char>>& board, string word) {int m = board.size();int n = board[0].size();vector<vector<bool>> book(m,vector<bool>(n,false));for(int i = 0; i < m; i++){for(int j = 0; j < n;j++){if(exist(board,i,j,0,word,book)){return true;}}}return false;}
private:bool exist(vector<vector<char>>& board,int i,int j,int step,string word,vector<vector<bool>>& book){if(step == word.size() )//注意:这个step必须为连续不断的step,不能断{return true;}if(i < 0 || j < 0 || i >= board.size() || j >= board[0].size()){return false;}if(book[i][j]){return false;}if(board[i][j] != word[step]){return false;}book[i][j] = true;bool res = exist(board,i+1,j,step+1,word,book) || exist(board,i,j+1,step+1,word,book) ||exist(board,i-1,j,step+1,word,book) || exist(board,i,j-1,step+1,word,book);book[i][j] = false;return res;}
};

2.深度优先搜索小结

深度优先搜索适用:

如果是递归数据结构,比如单链表,二叉树,集合,则一定可以用深度搜索,如果是非递归数据结构,如一维数组,二维数组,字符串,图等则概率小一些

明确深搜是求路径本身还是路径条数,前者则用一个数组 path来进行记录存储,后者不用存储路径

终止条件是什么?终止条件只的是不能扩展的末端节点,对于树,则是叶子节点

收敛条件是什么?收敛条件是指找到了一个合法解,很多时候终止条件和收敛条件是合二为一的,但两者代表的含义是不同的

剪枝加速,深度搜索的优点 是能在答案生成一半时就进行判断,舍弃不满足要求的答案,减少冗余搜索;利于题设中的各种信息,一旦判断此时的答案不会满足要求,则提前返回,避免冗余搜索

深度搜索代码模板:

void dfs(type *input,type* path,int step(int start),type *result)
{if(数据非法) return;if(step == input.size() (or start == input.size()))//收敛条件{将path放入 res中return;}if(可以剪枝) return;for(...) //执行所有可能的扩展操作{执行动作,修改pathdfs(input,path,step+1(or start+1),res);恢复path;        }
}

3.深度优先搜索和回溯法的区别

回溯法= 深度搜索  + 剪枝

深度搜索 准确的来讲,在搜索过程中会保留下来完整的树结构,即使遍历结果不满足答案,也会继续搜素下去,

而回溯法 是在深度搜索的过程中进行判断中间结果,如果中间结果不满足条件要求,则进行返回,不再搜索下去,

但是由于现在我们在深度搜索的过程中,或多或少会进行剪枝,所以这样来看两者并没有什么区别

4.深度优先搜索与递归的区别

深搜常常用递归来实现,二者常常同时出现,但是两者并不是同一个东西。

深搜,是一种算法,而递归是一种物理意义上的实现,递归和迭代是对应的。深搜可以用递归来实现,也可以用栈来实现,而递归,一般总用来实现深搜。

可以说,递归一定是深搜,深搜不一定用递归

递归有两种加速策略:一种是剪枝,对中间结果进行判断,提前返回(回溯),一种是加缓存,缓存中间结果,防止重复计算(动态规划),当然动态规划也可以用迭代来实现

还有一个问题:既然递归一定是深搜,那为什么要有两种术语呢?一般而言,在递归味道更浓的地方,一般用递归,比如在单链表,二叉树等递归数据结构上,而在图,数组等数据结构上,递归的比重不大,深搜的味道更浓,所以用深搜,但两者大部分情况下指同一回事。

深度搜索处理问题的关键 --- 做leetcode深度搜索类题目小结相关推荐

  1. 各大电子商务网站的站内搜索比较,因为要做站内搜索,所以前去观摩下

    参考的网站有:京东商城,亚马逊,苏宁易购,易迅网,凡客诚品,1号店,新蛋中国,库巴,好孩子,QQ商城,当当网,麦包包等网站,另外淘宝,一淘,阿里巴巴,天猫商城也看了下. 下面列出几个衡量的功能点,并根 ...

  2. LeetCode 基本四则运算类题目总结

    2. Add Two Numbers 题意:给出两个非空的链表代表两个非负数,每位数字再链表中逆序存放. 思路1:将链表各个数读出来,存到两个int里,最后相加得出答案,再转化为链表返回.问题:数据容 ...

  3. AI时代的神马搜索!神马智能对话技术深度解读

    智能对话是搜索引擎的未来形态,神马搜索在发展全网搜索.国内信息流.国际信息流等大数据业务的同时,智能对话的探索和沉淀也逐渐浮出水面.过去一年基于搜索推荐多年的积累,我们完成了平台架构.生产体系.算法体 ...

  4. 星云测试-给你的Android应用做个深度体检

    星云测试-给你的Android应用做个深度体检   星云测试- Android应用深度体检专业平台 星云在线云测试(简称星云测试www.teststars.cc)是全球第一个发布并商用的数字化精准软件 ...

  5. java性能瓶颈分析_Java性能优化技巧整理,做一个深度的程序员

    原标题:Java性能优化技巧整理,做一个深度的程序员 在我们身边是一大批的程序员,层次不一,但是放眼观,我们很容易就可以看到那些是业务型程序员,那些是有层次的程序员.注重细节,注重性能,做一个有深度的 ...

  6. 系统学习深度学习(四十)--基于模拟的搜索与蒙特卡罗树搜索(MCTS)

    转自:https://www.cnblogs.com/pinard/p/10470571.html 1. 基于模拟的搜索概述 什么是基于模拟的搜索呢?当然主要是两个点:一个是模拟,一个是搜索.模拟我们 ...

  7. 笔记 | 百度飞浆AI达人创造营:深度学习模型训练和关键参数调优详解

    笔记 | 百度飞浆AI达人创造营:深度学习模型训练和关键参数调优详解 针对特定场景任务从模型选择.模型训练.超参优化.效果展示这四个方面进行模型开发. 一.模型选择 从任务类型出发,选择最合适的模型. ...

  8. 深度学习模型训练和关键参数调优详解

    深度学习模型训练和关键参数调优详解 一.模型选择 1.回归任务 人脸关键点检测 2.分类任务 图像分类 3.场景任务 目标检测 人像分割 文字识别 二.模型训练 1.基于高层API训练模型 加载数据集 ...

  9. 搜索下半场:微信要做大搜索吗?

    作者:婷婷的勇敢世界 微信搜一搜团队 Samuel 在微信公开课中提及搜一搜的使用场景:"用微信就能搜".微信搜一搜希望用户有任何问题和困难的时候,都会想到用微信来搜. 此外,微信 ...

最新文章

  1. 【组队学习】【27期】集成学习
  2. 自学机器学习课程怕踩雷?有人帮你选出了top 5优质课
  3. 机器学习之挖掘melb_data.csv数据
  4. @PropertySource读取外部配置文件中的k-v保存到运行的环境变量中,加载完微博的配置文件以后使用${}取配置文件中的键值
  5. IT兄弟连 Java语法教程 变量1
  6. 工信部发布新能源车准入新规 9月1日起正式实施
  7. Win10修改防火墙入站规则
  8. 数据中心两种常用流量模型运用mininet的实现
  9. netlify支持php吗,hexo netlify 搭建简易博客
  10. .NET平台下开源框架
  11. Java进阶篇设计模式之十三 ---- 观察者模式和空对象模式
  12. android 模仿今日头条ViewPager+TabLayout
  13. cmpp3.0 java 华为_CMPP3.0/2.0完成短信收发功能(引用华为smsproxy开发包)
  14. 简述神经元网络控制的作用和特点
  15. 实习日记(4-28)
  16. PS的一些常用快捷键和学习笔记
  17. Q3中国网游业观察:腾讯网易春风得意
  18. 数学建模--正态分布均值的假设检验
  19. coreldraw x7 分布_了解CorelDRAW X7工作界面
  20. lambda函数用法及注意事项(简单总结,有待补充)

热门文章

  1. 国内部分视频剪辑软件使用总结
  2. 浏览器输入网址后发生了什么?
  3. Python练习题——初学Python记录
  4. FPGA平台开发基础
  5. 【SLAM学习笔记4】卡方检验chi-square
  6. mysql java配置文件_Mysql配置文件参数优化
  7. Mac 重置mysql数据库密码
  8. 鸿蒙系统1004无标题,华为P50 Pro外观基本确认:居中开孔全面屏首发鸿蒙操作系统...
  9. #Sam有话说#人以群分,共性与个性的智慧
  10. 星宸科技SSD202D芯片+无线投屏协议在摩托车智能仪表,电动车智能仪表批量出货。