深度优先搜索

概述

  • [一条路走到底,不撞南墙不回头]
  • [撞南墙]有两种情况:①遇到了边界条件,②遇到了已经走过的路
  • 深度优先的另一种结束条件,就是找到了目标出口
  • 深度优先遍历的本质就是穷举

常见的深度优先搜索

树的深度优先遍历

  1. [二叉树最大深度][https://leetcode-cn.com/problems/er-cha-shu-de-shen-du-lcof/]

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数

说明: 叶子节点是指没有子节点的节点

class Solution{public int maxDepth(TreeNode root){if(null==root) return 0;return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1;}
}
  1. [二叉树最小深度][https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/]

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

**说明:**叶子节点是指没有子节点的节点。

class Solution{public int minDepth(TreeNode root){if(null==root) return 0;int leftH = minDepth(root.left);int rightH = minDepth(root.right);if(0==rightH||0==leftH){return rightH+leftH+1;}else{return Math.min(leftH,rightH)+1;}}
}
  1. [路径总和][https://leetcode-cn.com/problems/path-sum/]

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum ,判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。

class Solution {public boolean hasPathSum(TreeNode root, int targetSum) {if(null==root) return false;if(null==root.left && null==root.right){return targetSum==root.val;}return hasPathSum(root.left, targetSum-root.val) || hasPathSum(root.right, targetSum-root.val);}
}
  1. [翻转二叉树][https://leetcode-cn.com/problems/er-cha-shu-de-jing-xiang-lcof/]

输入一个二叉树,该函数输出它的镜像。

class Solution {public TreeNode mirrorTree(TreeNode root) {if(root==null) return null;TreeNode left = root.left;TreeNode right = root.right;if(left==null && right==null){return root;}root.left = mirrorTree(right);root.right = mirrorTree(left);return root;}
}
  1. [相同的树][https://leetcode-cn.com/problems/same-tree/]

给你两棵二叉树的根节点 pq ,编写一个函数来检验这两棵树是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的

class Solution {public boolean isSameTree(TreeNode p, TreeNode q) {if(p==null && q==null) return true;if(p==null || q==null) return false;if(p.val != q.val) return false;return isSameTree(p.left,q.left) && isSameTree(p.right,q.right); }
}
  1. [对称二叉树][https://leetcode-cn.com/problems/dui-cheng-de-er-cha-shu-lcof/]

请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的.

class Solution {private boolean dfs(TreeNode left,TreeNode right){if(left==null && right==null) return true;if(left==null || right==null) return false;if(left.val!=right.val) return false;return dfs(left.right,right.left) && dfs(left.left,right.right);}public boolean isSymmetric(TreeNode root) {if(root==null) return true;return dfs(root.left,root.right);}
}
  1. [求根到叶子节点数字之和][https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/]

给定一个二叉树,它的每个结点都存放一个 0-9 的数字,每条从根到叶子节点的路径都代表一个数字。

例如,从根到叶子节点路径 1->2->3 代表数字 123。

计算从根到叶子节点生成的所有数字之和。

class Solution {public int sumNumbers(TreeNode root) {return dfs(root,0);}private int dfs(TreeNode root,int fromNums){if(root==null) return 0;fromNums = fromNums*10 + root.val;if(root.left==null &&root.right==null) return fromNums;return   dfs(root.right,fromNums)+ dfs(root.left,fromNums);}
}
  1. [二叉树的公共祖先][https://leetcode-cn.com/problems/er-cha-shu-de-zui-jin-gong-gong-zu-xian-lcof/]

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。

class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {if(root==null || root==p ||root ==q) return root;TreeNode left = lowestCommonAncestor(root.left, p, q);TreeNode right = lowestCommonAncestor(root.right, p, q);if(left==null) return right;if(right==null) return left;return root;}
}
  1. [从前序跟中序遍历序列构造二叉树][https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/]

根据一棵树的前序遍历与中序遍历构造二叉树

class Solution {public TreeNode buildTree(int[] preorder, int[] inorder) {if(preorder.length>0&&inorder.length>0){TreeNode root = new TreeNode(preorder[0]);int num=0;//从中序遍历序列中查找根节点位置for(int i =0; i<inorder.length; i++){if(inorder[i]==root.val){num=i;}}int[] preLeft = Arrays.copyOfRange(preorder,1,num+1);int[] preRight = Arrays.copyOfRange(preorder,num+1,preorder.length);int[] inoLeft = Arrays.copyOfRange(inorder,0,num);int[] inoRight = Arrays.copyOfRange(inorder,num+1,inorder.length);root.left=buildTree(preLeft,inoLeft);root.right=buildTree(preRight,inoRight);return root;}else{return null;}}
}
  1. [从中序跟后序遍历序列构造二叉树][https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/submissions/]
#由于python数组索引切片跟数组的index非常方便,感受一下python的魅力
class Solution(object):def buildTree(self, inorder, postorder):if postorder:root=TreeNode(postorder[-1])index = inorder.index(postorder[-1])root.left = self.buildTree(inorder[:index],postorder[:index])root.right = self.buildTree(inorder[index+1:],postorder[index:-1]) return root
  1. [前序遍历构造二叉搜索树][https://leetcode-cn.com/problems/construct-binary-search-tree-from-preorder-traversal/]

返回与给定前序遍历 preorder 相匹配的二叉搜索树(binary search tree)的根结点。

(回想一下,二叉搜索树是二叉树的一种,其每个节点都满足以下规则,对于 node.left 的任何后代,值总 < node.val,而 node.right 的任何后代,值总 > node.val。此外,前序遍历首先显示节点 node 的值,然后遍历 node.left,接着遍历 node.right。)

题目保证,对于给定的测试用例,总能找到满足要求的二叉搜索树。

class Solution(object):def bstFromPreorder(self, preorder):if preorder:root = TreeNode(preorder[0])root.left = self.bstFromPreorder([x for x in preorder[1:] if x<preorder[0] ])root.right = self.bstFromPreorder([x  for x in preorder[1:] if x>preorder[0]])return root

图的深度优先遍历

  1. [无向图中连接分量的数目][https://leetcode-cn.com/problems/number-of-connected-components-in-an-undirected-graph/]
class Solution {public int countComponents(int n, int[][] edges) {// 所有节点都没被访问boolean[] visited = new boolean[n];//构建邻接表List<Integer> [] adj = new ArrayList[n];for (int i = 0; i < n; i++) {adj[i] = new ArrayList<>();}for(int[] edge: edges){adj[edge[0]].add(edge[1]);adj[edge[1]].add(edge[0]);}//深度优先遍历int count=0;for(int i=0;i<n;i++){if(!visited[i]){dfs(adj,i,visited);count++;}}return count;}private void dfs(List<Integer> [] adj,int u,boolean[] visited){visited[u] = true;List<Integer> path = adj[u];for(int p:path){if(!visited[p]){dfs(adj,p,visited);}}}
}
  1. [冗余连接][https://leetcode-cn.com/problems/redundant-connection/]

    在本问题中, 树指的是一个连通且无环的无向图。

    输入一个图,该图由一个有着N个节点 (节点值不重复1, 2, …, N) 的树及一条附加的边构成。附加的边的两个顶点包含在1到N中间,这条附加的边不属于树中已存在的边。

    结果图是一个以边组成的二维数组。每一个边的元素是一对[u, v] ,满足 u < v,表示连接顶点u 和v的无向图的边。

    返回一条可以删去的边,使得结果图是一个有着N个节点的树。如果有多个答案,则返回二维数组中最后出现的边。答案边 [u, v] 应满足相同的格式 u < v。

    class Solution {private Map<Integer, List<Integer>> adj; //保存每个顶点能到达的所有顶点private Set<Integer> visited; //为了减少dfs次数,没有出现过的节点直接add这条边public int[] findRedundantConnection(int[][] edges) {this.adj = new HashMap<>();this.visited = new HashSet<>();for (int[] edge : edges) {int u = edge[0];int v = edge[1];if (adj.containsKey(u) && adj.containsKey(v)) {visited.clear();if (dfs(u, v)) {return edge;}}addEdg(v, u);addEdg(u, v);}return null;}private void addEdg(int u, int v) {if (adj.containsKey(u)) {adj.get(u).add(v);return;}List<Integer> successors = new ArrayList<>();successors.add(v);adj.put(u, successors);}private boolean dfs(int from, int to) {if (to == from) return true;visited.add(from);for (Integer point : adj.get(from)) {if (!visited.contains(point)) {if (dfs(point, to)) return true;}}return false;}
    }
    
  2. [找到最终安全状态][https://leetcode-cn.com/problems/find-eventual-safe-states/]

    public class Solution {private Boolean[] visited;public List<Integer> eventualSafeNodes(int[][] graph) {int len = graph.length;visited = new Boolean[len];List<Integer> res = new ArrayList<>();for (int i = 0; i < len; ++i) {if (dfs(i, graph)) {continue;}res.add(i);}return res;}/*** @param u* @param graph* @return 从顶点 u 出发的所有路径是不是有一条能够回到 u,有回路就返回 true*/private boolean dfs(int u, int[][] graph) {if (visited[u] != null) {return visited[u];}// 先默认从 u 出发的所有路径有回路visited[u] = true;// 结点 u 的所有后继结点都不能回到自己,才能认为结点 u 是安全的for (int successor : graph[u]) {if (dfs(successor, graph)) {return true;}}visited[u] = false;return false;}
    }
    

栈与深度优先搜索

栈这种后进先出的数据结构,对于迭代法写深度优先搜索有很重要的作用,同样,栈也被用于回溯算法,先看一看,怎么样使用栈来迭代深度优先算法吧:

  1. 前序遍历二叉树的迭代写法

    //前序遍历的迭代写法public List<Integer> preorderTraversal(TreeNode root) {List<Integer> res = new ArrayList<>();Deque<TreeNode> stack = new LinkedList<>();while (!stack.isEmpty() || null != root) {while (null != root) {stack.push(root);//由于前序遍历是先遍历根节点,所以在压入栈的时候就可以输出该节点的值res.add(root.val);// 根->左节点root = root.left;}//因为是从根节点过来的 pop出栈之后即可获得上一层节点root = stack.pop();root = root.right;}return res;}
    
  2. 中序遍历二叉树的迭代写法

    //中序遍历的迭代写法public List<Integer> inorderTraversal(TreeNode root) {List<Integer> res = new ArrayList<>();Deque<TreeNode> stack = new LinkedList<>();while (!stack.isEmpty() || null != root) {while (null != root) {stack.push(root);root = root.left;}root = stack.pop();//最下面的左节点先输出res.add(root.val);root = root.right;}return res;}
  3. 后序遍历二叉树的迭代写法

    public List<Integer> postorderTraversal(TreeNode root) {List<Integer> res = new ArrayList<>();Deque<TreeNode> stack = new LinkedList<>();TreeNode prev = null;while (!stack.isEmpty() || null != root) {while (null != root) {stack.push(root);root = root.left;}root = stack.pop();if(root.right == null || root.right==prev){//先输出左节点res.add(root.val);prev = root;root = null;}else{stack.push(root);//再输出右节点root = root.right;}}return res;}
    

(算法)深度优先搜索相关推荐

  1. 啊哈 , 算法 !--深度优先搜索( C语言版 )

    深度优先搜索 : 理解的关键在于解决"当下该如何做".至于"下一步该如何做"则与"当下该如何做"是一样的 问题 : 求出123的全排列 12 ...

  2. 基础算法·深度优先搜索

    祝食用愉快XD 题目链接 (是一道胡乱出的题) U56815 来走迷宫鸭! 解题思路 深度优先搜索,如果能不碰墙地到达右下角的出口,就把旗子立起来表示找到了出口. 什么?你没听过深度优先搜索 没事,且 ...

  3. 【图论算法】深度优先搜索的应用

    文章目录 深度优先搜索 无向图 双连通性 双连通以及割点的概念 找出图中割点的算法 一个例子 欧拉回路 认识欧拉回路 找出欧拉回路的算法 一个例子 有向图 查找强分支 dfs简单应用--部分和问题 深 ...

  4. ★深度优先搜索+解空间树+递归,三合一详解

    为什么这三个内容要放在一起讲? 如果单独分开讲那么 递归 和 深度优先搜索 这两个内容就会变得及其抽象,不适合新手入门 首先明确这三个内容的定义,由于深搜和递归过于抽象先说解空间树. 一.什么是解空间 ...

  5. DFS(深度优先搜索)详解(概念讲解,图片辅助,例题解释,剪枝技巧)

    目录 那年深夏 引入 1.什么是深度优先搜索(DFS)? 2.什么是栈? 3.什么是递归? 图解过程 问题示例 1.全排列问题 2.迷宫问题 3.棋盘问题(N皇后) 4.加法分解 模板 剪枝 1.简介 ...

  6. 深度优先搜索_0基础学算法 搜索篇第一讲 深度优先搜索

    0基础学算法 搜索篇第一讲 深度优先搜索 相信绝大多数人对于深度优先搜索和广度优先搜索是不会特别陌生的,如果我这样说似乎你没听说过,那如果我说dfs和bfs呢?先不说是否学习过它们,至少它们的大名应该 ...

  7. 打印数组算法:堆栈与深度优先搜索(迷宫问题)

    每日一贴,今天的内容关键字为打印数组 栈堆的拜访规矩被制约为Push和Pop两种作操,Push(入栈或压栈)向栈顶添加元素,Pop(出栈或弹出)则掏出前当栈顶的元素,也就是说,只能拜访栈顶元素而不能拜 ...

  8. Java实现算法导论中图的广度优先搜索(BFS)和深度优先搜索(DFS)

    对算法导论中图的广度优先搜索(BFS)和深度优先搜索(DFS)用Java实现其中的伪代码算法,案例也采用算法导论中的图. import java.util.ArrayList; import java ...

  9. 【数据结构与算法】2.深度优先搜索DFS、广度优先搜索BFS

    原文链接:https://blog.csdn.net/qq_41681241/article/details/81432634 总结 一般来说,广搜常用于找单一的最短路线,或者是规模小的路径搜索,它的 ...

最新文章

  1. 服务器BMC、BIOS、IPMI、UEFI技术解析
  2. c语言基础学习08_关于内存管理的复习
  3. php addall,ThinkPHP3.2框架使用addAll()批量插入数据的方法
  4. boost::outcome模块containers相关的测试程序
  5. 球球大作战为什么显示服务器神游,球球大作战不能玩怎么解决_球球大作战不能玩解决方案详细分析_好特教程...
  6. mysql怎么消除冗余,mysql剔除冗余数据
  7. Linux 下用C语言连接 sqlite
  8. 设置和获取函数体现的软件工程
  9. 【语音去噪】基于matlab小波软阈值语音降噪【含Matlab源码 531期】
  10. python入门神器下载_Python编程神器 v3.7.2 最新免费版
  11. 一个简单的dw网页制作作业,学生个人html静态网页制作成品代码——怪盗基德动漫主题网页成品(15页)
  12. 最新HyperSnap绿色汉化版
  13. 数字图像处理 信息隐藏 LSB算法
  14. 浅谈setOnClickListener使用方法
  15. signature=461282e191fe3d72a8b43e5b831644fb,Proposed Graphene Nanospaser
  16. word打开文档很久很慢_打开Office文档很慢的解决办法
  17. Axure-涟漪动画效果
  18. BBP算法计算圆周率(BBP Formula HDU - 6217)
  19. 站间切换反传介绍(PDU级/DRB级反传)
  20. 程序员的 100款代码表白特效,一个比一个浪漫

热门文章

  1. 前后端优秀团队(持续添加中。。。。)
  2. 东方雨虹总市值首次突破1000亿;巴黎珠宝蔻尔珮将在中国销售三个标志性系列 | 美通企业日报...
  3. 大华监控资料搜集记录
  4. JSONObject 与 JSONArray
  5. MQ 系列之 JMSTemplate
  6. JavaWeb、Tomcat、jquery:Failed to load resource: the server responded with a status of 500 ()
  7. ESP32使用有源蜂鸣器演奏《反方向的钟》
  8. 使用cout在命令行输出彩色字体
  9. You have an error in your SQL syntax +改动数据库表名后异常(已解决)【MySQL+SSM】
  10. 疾风之刃的最新服务器,疾风之刃6月16日更新 数据互通服务器一览