主要收录深度优先遍历和宽度优先遍历,深度优先遍历一般可以与回溯、递归、树等方法联用,达到优雅遍历的效果,而宽度优先搜索可以用到最短路问题的求解中。
为什么不用 bfs 去遍历?第一是因为 bfs 写起来麻烦,不如 dfs 直观。第二是在某些查找到满足情况即可退出的应用而言,bfs 需要一层一层的去检查,效率很低。 
为什么不用 dfs 去求最短路?如上所示,bfs 可以一层一层的检查,相对 dfs 更容易查到最短路。 
 
 
dfs 岛屿问题 130. 被围绕的区域 给你一个 m x n 的矩阵 board ,由若干字符 'X' 和 'O' ,找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。
那么如何填充内部的 O 呢?这里就要用到 dfs,首先遍历 board,如果遇到了 O,那个和这个 O 相邻的 O 也要被填充,此时就要使用 dfs 来查找相邻的 O 
由于只填充被 X 包围的 O,因此,边界上的 O 不能被填充。那么我们预先把和边界相连的 O 都填充为其他符号,在处理完 board 内部的 O 的时候,在把其他符号替换为 O 即可。 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 class  Solution  {public :    int  n, m;     void  solve (vector<vector<char >>& board)   {         n = board.size ();         m = board[0 ].size ();                  for  (int  i = 0 ; i < n; i++) {             dfs (i, 0 , board, '+' );             dfs (i, m-1 , board, '+' );         }         for  (int  i = 0 ; i < m; i++) {             dfs (0 , i, board, '+' );             dfs (n-1 , i, board, '+' );         }                  for  (int  i = 0 ; i < n; i++) {             for  (int  j = 0 ; j < m; j++) {                 if  (board[i][j] == 'O' ) {                     dfs (i, j, board, 'X' );                 }             }         }                  for  (int  i = 0 ; i < n; i++) {             for  (int  j = 0 ; j < m; j++) {                 if  (board[i][j] == '+' ) {                     board[i][j] = 'O' ;                 }             }         }     }          void  dfs (int  r, int  c, vector<vector<char >>& board, char  pad)   {         if  (r < 0  || c < 0  || r >= n || c >= m) {             return ;         }         if  (board[r][c] == 'O' ) {             board[r][c] = pad;             dfs (r + 1 , c, board, pad);             dfs (r - 1 , c, board, pad);             dfs (r, c + 1 , board, pad);             dfs (r, c - 1 , board, pad);         }     } }; 
 
bfs 111. 二叉树的最小深度 给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。说明:叶子节点是指没有子节点的节点。
求二叉树或者多叉树中根节点到叶子节点的最短路径,一般都是 bfs 遍历算法。给出 bfs 的模板:
1 2 3 4 5 6 7 8 9 10 11 12 queue.push (root); while  (queue.size ()) {    int  s = queue.size ();     for  (int  i = 0 ; i < s; i++) {         auto  node = queue.top ();         queue.pop ();         if  (node->left != null)             queue.push (node->left);         if  (node->right != null)             queue.push (node->right);     } } 
 
在进入 bfs 之前先处理一些极端的特殊情况,比如根节点为空,根节点就是目标节点等 
在处理完特殊情况后,之后就是 bfs 遍历,如果遍历期间的节点满足目标情况,返回结果即可。 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class  Solution  {public :    int  minDepth (TreeNode* root)   {         if  (root == nullptr )             return  0 ;         if  (root->left == nullptr  && root->right == nullptr )             return  1 ;         int  depth = 1 ;         deque<TreeNode*> q;         q.push_back (root);         while  (q.size ()) {             int  s = q.size ();             for  (int  i = 0 ; i < s; i++) {                 auto  node = q.front ();                 q.pop_front ();                                  if  (node->left == nullptr  && node->right == nullptr ) {                     return  depth;                 }                 if  (node->left != nullptr )                     q.push_back (node->left);                 if  (node->right != nullptr )                     q.push_back (node->right);             }             depth += 1 ;         }         return  depth;     } }; 
 
752. 打开转盘锁 你有一个带有四个圆形拨轮的转盘锁。每个拨轮都有 10 个数字: ‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’ 。每个拨轮可以自由旋转:例如把 ‘9’ 变为 ‘0’,’0’ 变为 ‘9’ 。每次旋转都只能旋转一个拨轮的一位数字。
锁的初始数字为 ‘0000’ ,一个代表四个拨轮的数字的字符串。列表 deadends 包含了一组死亡数字,一旦拨轮的数字和列表里的任何一个元素相同,这个锁将会被永久锁定,无法再被旋转。
字符串 target 代表可以解锁的数字,你需要给出解锁需要的最小旋转次数,如果无论如何不能解锁,返回 -1 。示例:
1 2 3 4 5 6 输入:deadends = ["0201","0101","0102","1212","2002"], target = "0202" 输出:6 解释: 可能的移动序列为 "0000" -> "1000" -> "1100" -> "1200" -> "1201" -> "1202" -> "0202"。 注意 "0000" -> "0001" -> "0002" -> "0102" -> "0202" 这样的序列是不能解锁的, 因为当拨动到 "0102" 时这个锁就会被锁定。 
 
寻找最短路径时,同样需要使用 bfs 算法。我们把这个问题看成一个多叉树问题,如果 00 是根节点,那么叶子节点就是 01, 10, 09, 90,同理,也能得到 0000 为根节点时对应的叶子节点 
同样,先处理极端情况,如根节点被死锁,以及根节点就是目标的特殊情况 
之后,以 0000 为根节点开始 bfs 算法,我们手写两个函数,分别为 _up 和 _down 来对 0000 的每一位进行转动进而得到子节点,如果子节点满足要求,返回此时的深度即可 
与二叉树不同的是,二叉树使用 root->left, root->right 能保证不会遍历重复节点,而对于此问题,很有可能从 0000 查找到 5555,又从 5555 查找回 0000,因为只要一直转动下去,0000 也是 5555 的子节点。因此,在遍历期间需要设置一个 map,将遍历过的节点添加进去,保证不会重复遍历一个节点,不走回头路。 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 class  Solution  {public :    string _up(string node, int  idx) {         string s = node;         if  (s[idx] == '9' )             s[idx] = '0' ;         else              s[idx] += 1 ;         return  s;     }     string _down(string node, int  idx) {         string s = node;         if  (s[idx] == '0' )             s[idx] = '9' ;         else              s[idx] -= 1 ;         return  s;     }     int  openLock (vector<string>& deadends, string target)   {         deque<string> q;         q.push_back ("0000" );         unordered_map<string, int > m;         for  (auto  i : deadends)             m[i] = 10 ;         if  (m["0000" ] == 10 )             return  -1 ;         int  cnt = 1 ;         if  (target == "0000" )             return  0 ;         while  (q.size ()) {             int  s = q.size ();             for  (int  i = 0 ; i < s; i++) {                 auto  node = q.front ();                 q.pop_front ();                 for  (int  i = 0 ; i < 4 ; i++) {                     string s1 = _up(node, i);                     if  (s1 == target)                         return  cnt;                     if  (m[s1] != 10 ) {                         m[s1] = 10 ;                         q.push_back (s1);                     }                     string s2 = _down(node, i);                     if  (s2 == target)                         return  cnt;                     if  (m[s2] != 10 ) {                         m[s2] = 10 ;                         q.push_back (s2);                     }                 }             }             cnt += 1 ;         }         return  -1 ;     } };