简介:深度优先搜索算法(Depth-First-Search, DFS),最初是一种用于遍历或搜索树和图的算法,在LeetCode
中很常见,虽然感受不难,可是理解起来仍是有点难度的。html
简要归纳,深度优先的主要思想就是“不撞南墙不回头”,“一条路走到黑”,若是遇到“墙”或者“无路可走”时再去走下一条路。java
假如对树进行遍历,沿着树的深度遍历树的节点,尽量深的搜索树的分支,当达到边际时回溯上一个节点再进行搜索。以下图的一个二叉树。
node
首先给出这个二叉树的深度优先遍历的结果(假定先走左子树):1->2->4->5->3->6->7
git
根据深度优先遍历的概念:沿着这树的某一分支向下遍历到不能再深刻为止,以后进行回溯再选定新的分支。算法
定义节点编程
class TreeNode{ int val; TreeNode left; TreeNode right; }
递归的方式数据结构
分别对左右子树进行递归,一直到底才进行回溯。若是不了解递归能够参考个人博客你真的懂递归吗?。code
class Solution{ public void depthOrderTraversalWithRecusive(TreeNode root){ if(root == null){ return; } System.out.print(root.val +"->"); depthOrderTraversalWithRecusive(root.left); depthOrderTraversalWithRecusive(root.right); } }
迭代的方式htm
上面实现了递归方式的深度优先遍历,也能够利用栈把递归转换为迭代的方式。blog
可是为了保证出栈的顺序,须要先压入右节点,再压左节点。
class Solution{ public void depthOrderTraversalWithoutRecusive(TreeNode root){ if(root == null) return; Stack<TreeNode> stack = new Stack<>(); stack.push(root); while(!stack.isEmpty()){ TreeNode node = stack.pop(); System.out.print(node.val + "->"); if(node.right != null){ stack.push(node.right); } if(node.left != null){ stack.push(node.left); } } } }
接着再列举个利用深度优先遍历的方式的题目
给定一个表示游戏板的二维字符矩阵,'M'
表示一个未挖出的地雷,'E'
表示一个未挖出的空方块,'B'
表明没有相邻(上,下,左,右,和全部4个对角线)地雷的已挖出的空白方块,数字('1'
到 '8'
)表示有多少地雷与这块已挖出的方块相邻,'X'
则表示一个已挖出的地雷。
根据如下规则,返回相应位置被点击后对应的面板:
'M'
)被挖出,游戏就结束了- 把它改成 'X'
。'E'
)被挖出,修改它为('B'
),而且全部和其相邻的方块都应该被递归地揭露。'E'
)被挖出,修改它为数字('1'
到'8'
),表示相邻地雷的数量。示例
输入: [['E', 'E', 'E', 'E', 'E'], ['E', 'E', 'M', 'E', 'E'], ['E', 'E', 'E', 'E', 'E'], ['E', 'E', 'E', 'E', 'E']] Click : [3,0] 输出: [['B', '1', 'E', '1', 'B'], ['B', '1', 'M', '1', 'B'], ['B', '1', '1', '1', 'B'], ['B', 'B', 'B', 'B', 'B']]
思路:根据给定的规则,当给定一个Click
坐标,当不为雷的时候以此坐标为基点向四周8个方向进行深度遍历,把空格E
填充为B
,而且把与地雷M
相连的空方块标记相邻地雷的数量。
注意 :
在这个题中能够沿着8个方向递归遍历,全部要注意程序中,采用了两个for循环能够实现向8个方向递归。
for(int i=-1;i<=1;i++){ for(int j=-1;j<=1;j++){ } }
本程序须要进行返回board
,在最后须要进行返回。
编程步骤
Click
给出的坐标找出的是地雷,直接返回。class Solution{ public char[][] updateBoard(char[][] board,int[] click){ if(board[click[0]][click[1]] == 'M'){ board[click[0]][click[1]] = 'X'; return board; } return click(board,click[0],click[1]); } private char[][] click(char[][] board,int x,int y){ int num = getNum(board, x,y); if(num == 0){ board[x][y] = 'B'; }else{ board[x][y] = Character.forDigit(num,10); return board; } //递归 for(int i=-1;i<=1;i++){ for(int j=-1;j<=1;j++){ if(x + i >= 0 && x + i < board.length&&y + j >=0&&y+j<board[0].length&&board[x+i][y+j]=='E'){ board = click(board,x+i,y+j); } } } return board; } private int getNum(char[][] board,int x,int y){ int num = 0; for(int i=-1;i<=1;i++){ for(int j=-1;j<=1;j++){ if(x + i >= 0&&y + j >=0&&x+i<board.length&&y+j<board[0].length&&board[x+i][y+j]=='M'){ num ++; } } } return num; } }
总结 :深度优先遍历不只存在树和图的数据结构中,还有不少也能够用到它。须要肯定的是每一步该怎么走,有几个方向能够走。