200. 岛屿数量 深度优先遍历

给你一个由 '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'

 深度优先遍历可用于树,图,或者网格中,

图的深度优先遍历 从初始的访问结点出发,初始访问结点可能有多个邻接结点,首先访问第一个邻接结点,然后再以这个被访问的邻接结点作为初始结点,访问它的第一个邻接结点,每次访问完当前结点之后首先访问当前节点的第一个邻接结点,这种策略是优先纵向深入。是一个递归的过程

1.首先访问初始结点,(做这个算法问题的判断),并将这个节点标记为已访问,防止重复判断。

2.查找结点的第一个邻接结点,若存在,则对当前结点进行深度优先遍历,(即根据当前算法问题做出判断),然后继续查找这个结点的第一个邻接结点,进行深度优先遍历,如果不存在,则退回到上一个结点,继续查找这个结点的另一个邻接结点,从当前结点向下搜索。

判断图的终止条件为当前结点没有邻接结点

使用邻接矩阵深搜

框架代码

class Grape{
    public ArrayList vertex; //存储顶点的合集
    public int[][] edges; //邻接矩阵
    public int edgeNum;  //边数
    public boolean[] isVisited; //记录当前顶点是否当问过

    //图的深度优先遍历框架
    public void frame(){
        isVisited = new boolean[vertex.size()];//初始化判断数组
        //开始遍历图的每一个顶点 对每个结点都进行深搜
        for(int i = 0;i < vertex.size();i++){
            if (isVisited[i]){
                //如果当前顶点已经访问过,则跳过访问下一个
                continue;
            }else{
                dfs(i);//遍历
            }
        }
    }
    public void dfs(int i){
        //省略 每个算法问题在此处进行判断
        isVisited[i] =true;//将当前结点设置为已访问
        int n = getFirst(i);//找出当前结点的第一个邻接结点
        if (n != -1){//当前结点还有未访问的邻接结点
            dfs(n);
        }else {
            return;
        }
    }
    //找当前结点的邻接结点 (通过邻接结点)
    private int getFirst(int i) {
        //遍历其他结点
        for(int j=0;j0&&!isVisited[j]) {
                //返回这个结点
                return j;
            }
        }
        return -1;
    }


}

树的深度优先遍历类似,从根节点开始遍历,然后再去判断当前树的左树,然后将当前左树作为根节点,继续判断当前节点的左子树,知道遍历到左子树尽头,然后退回到上一个结点,判断右子树

终止条件为当前根节点为空

框架代码

void dfs(TreeNode root) {
    // 判断条件
    if (root == null) {
        return;
    }
    // 访问两个结点:左子结点、右子结点
    dfs(root.left);
    dfs(root.right);
}

网格的深度优先遍历 类似 找出终止条件 和 判断方向

网格的终止条件就是不能遍历到的位置也就是越界的地方 网格有四个运动方向上下左右 如果超出了网格的范围就退回去 网格也需要判断是否重复遍历 遍历每一个结点之后做标记 如果已经访问过就不再访问

框架代码

void dfs(int[][] grid, int r, int c) {
    // 判断终止条件
    // 如果坐标 (r, c) 超出了网格范围,直接返回
    if (!inArea(grid, r, c)) {
        return;
    }
    // 访问上、下、左、右四个相邻结点
    dfs(grid, r - 1, c);
    dfs(grid, r + 1, c);
    dfs(grid, r, c - 1);
    dfs(grid, r, c + 1);
}

// 判断坐标 (r, c) 是否在网格中
boolean inArea(int[][] grid, int r, int c) {
    return 0 <= r && r < grid.length 
        	&& 0 <= c && c < grid[0].length;
}

本题为网格的深度优先遍历 深搜每结束一次 说明已经遍历完一个岛屿计数

public int numIslands(char[][] grid) {
        int res = 0;
        //遍历结点 从当前结点开始遍历
        for (int i = 0;i < grid.length;i++){
            for (int j = 0;j < grid[0].length;j++){
                //如果当前结点是岛屿就开始遍历
                if (grid[i][j] == '1'){
                    dfs(grid,i,j);
                    //计数
                    res++;
                }
            }
        }
        return res;
    }
    public void dfs(char[][] grid,int row,int col){
        //终止条件判断
        if (row < 0 || row >= grid.length || col < 0 || col >= grid[0].length){
            return;
        }
        //判断当前结点是都已经被判断
        if (grid[row][col] != '1'){
            return;
        }
        //将当前位置设置为已经访问过
        grid[row][col] = 2;
        //上下左右遍历
        dfs(grid,row - 1,col);
        dfs(grid,row + 1,col);
        dfs(grid,row,col - 1);
        dfs(grid,row,col + 1);

    }

你可能感兴趣的:(leetcode)