簡介:深度優先搜索算法(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; } }
總結 :深度優先遍歷不只存在樹和圖的數據結構中,還有不少也能夠用到它。須要肯定的是每一步該怎麼走,有幾個方向能夠走。