【数据结构(四)】一一一一队列BFS、DFS

【数据结构(四)】队列BFS、DFS

今天想说一说个人对于这两个搜索方法的见解。在我看来,DFS与BFS是算法道路上最基础最容易掌握的,同时,又能提供巨大助力的方法之一。我这里斗胆用方法二字来形容DFS(Deep First Search)深度优先搜索以及 BFS(Breath First Search)广度优先搜索,用搜索思想来囊括二者。方法是死的,而思想是活的,我们应该通过对这两种方法的剖析来获得这种思想,因为无论是在现实问题还是算法题目上,问题模型都是多变的,我们要着重于理解思想而后针对特定问题能用最佳的方法去解决。

❓ 题目–岛屿数量

​ 给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。

​ 岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

​ 此外,你可以假设该网格的四条边均被水包围。

示例 1:

​ 输入:grid = [
[“1”,“1”,“1”,“1”,“0”],
[“1”,“1”,“0”,“1”,“0”],
​ [“1”,“1”,“0”,“0”,“0”],
​ [“0”,“0”,“0”,“0”,“0”]
​ ]
​ 输出:1
​ 示例 2:

输入:grid = [
[“1”,“1”,“0”,“0”,“0”],
[“1”,“1”,“0”,“0”,“0”],
[“0”,“0”,“1”,“0”,“0”],
[“0”,“0”,“0”,“1”,“1”]
]
输出:3

提示:

​ m == grid.length
​ n == grid[i].length
​ 1 <= m, n <= 300
grid[i][j] 的值为 ‘0’ 或 ‘1’

image-20210808174009143

image-20210808174025077

1️⃣ DFS(深度优先搜索)

深度优先搜索的步骤分为:

  1. 递归下去

  2. 回溯上来。

顾名思义,深度优先,则是以深度为准则,先一条路走到底,直到达到目标。这里称之为递归下去。

否则既没有达到目标又无路可走了,那么则退回到上一步的状态,走其他路。这便是回溯上来。

☺️ 题解

💽 思路:

引用解题思路

  • 目标是找到矩阵中 “岛屿的数量” ,上下左右相连的 1 都被认为是连续岛屿。

  • DFS方法: 设目前指针指向一个岛屿中的某一点 (i, j),寻找包括此点的岛屿边界。

    • 从 (i, j) 向此点的上下左右 (i+1,j),(i-1,j),(i,j+1),(i,j-1) 做深度搜索。
    • 终止条件:
      • (i, j) 越过矩阵边界;
      • grid[i][j] == 0,代表此分支已越过岛屿边界。
    • 搜索岛屿的同时,执行 grid[i][j] = ‘0’,即将岛屿所有节点删除,以免之后重复搜索相同岛屿。
  • 主循环
    遍历整个矩阵,当遇到 grid[i][j] == ‘1’ 时,从此点开始做深度优先搜索 dfs,岛屿数 count + 1 且在深度优先搜索中删除此岛屿。

  • 最终返回岛屿数 count 即可。

🦅 DFS题解
package com.dataStructure.queue;

/**
 * @author xiaoCoder
 * @version 1.0
 * @description: TODO DFS(Deep First Search)深度优先搜索
 * @date 2021/8/8 15:21
 */
public class DemoDFSNumberOfIslands {
    public static void main(String[] args) {
        char[][] grid = {
                {'1', '1', '0', '0', '0'},
                {'1', '1', '0', '0', '1'},
                {'0', '0', '1', '0', '0'},
                {'0', '0', '0', '1', '1'}
        };
        DemoDFSNumberOfIslands demoDFSNumberOfIslands = new DemoDFSNumberOfIslands();
        int i = demoDFSNumberOfIslands.numIsIsland(grid);
        System.out.println("岛屿数量:"+i);
    }

    public int numIsIsland(char[][] grid) {
        int count = 0;
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[i].length; j++) {
                if (grid[i][j] == '1') {
                    // 进行置零然后再进行增加
                    DFS(i,j,grid);
                    count++;
                }
            }
        }
        return count;
    }

    /**
     * @param h    长
     * @param w    宽
     * @param grid 矩阵
     */
    public void DFS(int h, int w, char[][] grid) {
        // 排除没必要的条件
        if (h < 0 || w < 0 || h >= grid.length || w >= grid[0].length || grid[h][w] == '0') return;
        // 将符合的岛屿制 0 防止再次被调用
        grid[h][w] = '0';
        // 调用它的上下左右进行查询;
        DFS(h + 1, w, grid);
        DFS(h - 1, w, grid);
        DFS(h, w - 1, grid);
        DFS(h, w + 1, grid);
    }
}

2️⃣ BFS (广度优先搜索)

☺️ 题解

💽 思路:

引用解题思路

  • 主循环和思路一类似,不同点是在于搜索某岛屿边界的方法不同。
  • BFS方法:
    • 借用一个队列 queue,判断队列首部节点 (i, j) 是否未越界且为 1:
      • 若是则置零(删除岛屿节点),并将此节点上下左右节点 (i+1,j),(i-1,j),(i,j+1),(i,j-1) 加入队列;
      • 若不是则跳过此节点;
    • 循环 pop 队列首节点,直到整个队列为空,此时已经遍历完此岛屿。
🦅 BFS题解
package com.dataStructure.queue;

import java.util.LinkedList;
import java.util.Queue;

/**
 * @author xiaoCoder
 * @version 1.0
 * @description: TODO BFS(Breath First Search)广度优先搜索
 * @date 2021/8/8 15:50
 */
public class DemoBFSNumberOfIslands {
    public static void main(String[] args) {
        char[][] grid = {
                {'1', '1', '0', '1', '0'},
                {'1', '1', '0', '0', '1'},
                {'0', '0', '1', '0', '0'},
                {'0', '0', '0', '1', '1'}
        };
        DemoBFSNumberOfIslands bfsNumberOfIslands = new DemoBFSNumberOfIslands();
        int i = bfsNumberOfIslands.numIslands(grid);
        System.out.println(i);
    }

    public int numIslands(char[][] grid) {
        int count = 0;
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == '1') {
                    BFS(grid, i, j);
                    count++;
                }
            }
        }
        return count;
    }

    private void BFS(char[][] grid, int i, int j) {
        // 创建队列
        Queue<int[]> array = new LinkedList<>();
        array.add(new int[]{i, j});
        // 开始循环搜索
        while (!array.isEmpty()) {
            // 移除队列首位
            int[] head = array.poll();
            // 获取到首位对应的坐标位置
            int x = head[0], y = head[1];
            // 跳出当前不合法条件循环,继续下一次循环
            if (x < 0 || x >= grid.length || y < 0 || y >= grid[0].length || grid[x][y] == '0') continue; 
            // 将队列首个位置进行制零
            grid[x][y] = '0';
            // 进行广度搜索放入队列
            array.add(new int[]{x-1,y});
            array.add(new int[]{x+1,y});
            array.add(new int[]{x,y-1});
            array.add(new int[]{x,y+1});
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值