深度优先&广度优先

80 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第16天,点击查看活动详情

深度优先搜索DFS和广度优先搜索BFS,主要用于对树或图的遍历

深度优先搜索DFS

DFS解决的是连通性问题,给定起点和终点,判断是否有一条路径能从起点走到终点,或者是从起始状态到最终状态。连通的路径可以有很多条,只需要找出一条即可

算法的思想:

  • 从起点出发,选择一个可选方向不断往前走,直到无法继续走为止
  • 然后尝试另一个方向,直到走到终点,上下左右一路走到黑
  • 类似于走迷宫一样,不断往里走,所以称为深度优先

DFS的实现方式:

  1. 递归实现
    • 递归实现DFS代码看上去很简洁
    • 但是压入和弹出系统栈会需要较多时间,压栈很深会造成效率低下
  2. 非递归实现
    • 深度优先遍历的非递归实现必须依赖栈结构
    • 栈的特点是先进后出

广度优先搜索BFS

BFS解决的是最短路径问题和层序遍历

算法的思想:

  • 从起点出发,一层一层进行,每层中的点距离起始点的步数都相同
  • 同时从起点和终点出发的广度优先搜索被称为双端BFS,双端BFS可以大大提高效率

BFS的实现方式:

  • 广度优先遍历的非递归实现必须依赖队列结构
  • 队列的特点是先进先出

例题

需要标记visited的节点,避免被重复遍历或有环时死循环

岛屿的最大面积

DFS解法

var maxAreaOfIsland = function(grid) {
   if (!grid.length) {
       return 0
   }
   let m = grid.length
   let n = grid[0].length
   function dfs (x, y) {
     // 判断是否越界
     if (x < 0 || x > m-1 || y < 0 || y > n-1) {
         return 0
     }
     // 判断是否岛屿,不是岛屿则返回,是岛屿则标记访问过,置0
     if (grid[x][y] === 0) {
         return 0
     }
     grid[x][y] = 0
     let num = 1
     // 设置方向数组
     let dx = [-1, 1, 0, 0], dy = [0, 0, -1, 1]
     for (let i = 0; i < dx.length; i++) {
         // 上下左右四个方向递归dfs
         num += dfs(x + dx[i], y + dy[i])
     }
     return num
   }
   let res = 0
   for (let i = 0; i < m; i++) {
       for (let j = 0; j < n; j++) {
          res = Math.max(res, dfs(i, j))
       }
   }
   return res
};

image.png

时间复杂度:O(mn),空间复杂度:O(mn)

BFS解法

var maxAreaOfIsland = function(grid) {
   if (!grid.length) {
       return 0
   }
   let m = grid.length
   let n = grid[0].length
   let res = 0
   let dx = [-1, 1, 0, 0], dy = [0, 0, -1, 1]
   for (let i = 0; i < m; i++) {
       for (let j = 0; j < n; j++) {
            if (grid[i][j] === 0) {
                continue
            }
            let num = 0
            let queen = [[i, j]]
            while(queen.length) {
                let [x,y] = queen.shift()
                // 判断是否越界
                if (x < 0 || x > m-1 || y < 0 || y > n-1) {
                    continue
                }
                // 判断是否岛屿,不是岛屿则返回,是岛屿则标记访问过,置0
                if (grid[x][y] === 0) {
                    continue
                }
                grid[x][y] = 0
                num++
                for (let h = 0; h < dx.length; h++) {
                    queen.push([x+dx[h], y+dy[h]])
                }
            }
            res = Math.max(res, num)
       }
   }
   return res
};

image.png

时间复杂度:O(mn),空间复杂度:O(mn)