LeetCode 200. Number of Islands【深度优先搜索】

题目描述

在这里插入图片描述

知识点

深度优先搜索 或者 并查集

结果

在这里插入图片描述
我挺满意哒

实现

码前思考

我是在并查集的章节里面看到这个题目的,但是由于题目的性质,我最后选择了使用DFS来解题,那是什么性质导致我选择DFS来解题呢?

  1. 首先剥去小岛的外壳,我们可以发现这其实就是一个求连通分量的题目
  2. 对于这种在二维矩阵中上、下、左、右移动的题目,我们通常使用的是深度优先搜索,比如说之前做过的一道动态规划的题目——LeetCode 329. Longest Increasing Path in a Matrix,他用的就是记忆化DFS,通常DFS总能通过记忆化来降低时间复杂度的!
  3. 这里的“连通分量”类似于咱们的并查集中的“集”;
  4. 需要另外注意的是:
  5. 对于这种2d array的题目,最好是保持2d不变,不要映射成1d
  6. 四种方向可以通过数组来表示,从而增强代码可读性:int dr[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};

代码实现

//1. 题目的意思实际上就是找图中的连通分量
//2. 对于这种上下左右移动的题,我们要考虑一些深度优先搜素!
//3. 类似于并查集中的“集”
class Solution {
private:
    //记录在哪一个连通分量里面的
    vector<vector<int>> father;
    
    //记录连通分量的个数 number of component
    int nc;

    //DFS的方向,只有向下和向右两个方向
    int dr[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};

    int m;
    int n;
public:
    int numIslands(vector<vector<char>>& grid) {
        //获取grid大小
        m = grid.size();

        //特判
        if(m==0){
            return 0;
        }

        n = grid[0].size();

        //初始化father数组
        father.assign(m,vector<int>(n,-1));
        nc=0;

        //遍历每一个元素
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(father[i][j]!=-1){
                    continue;
                }else if(grid[i][j] == '1'){
                    DFS(i,j,grid);
                    nc++;
                }
            }
        }

        return nc;
    }

    //函数的意思是设置当前坐标及其邻居的father
    //这里DFS的返现有一些小技巧
    void DFS(int i,int j,vector<vector<char>>& grid){
        //如果当前为‘0’
        if(grid[i][j] == '0'){
            return;
        }
        
        //记忆化搜索,直接返回
        if(father[i][j] != -1){
            return;
        }

        //设置当前坐标及其邻居的father
        father[i][j] = nc;

        for(int k=0;k<4;k++){
            int x = i + dr[k][0];
            int y = j + dr[k][1];
            if(x < m && y < n && x>=0 && y>=0){
                DFS(x,y,grid);
            }
        }
    }
};

码后反思

关于代码的问题:

  1. 其实father只要设置成bool型的就好了,没必要设置成int
  2. 先前以为只要向下和向右走就可以了,以为可以耍小聪明,结果忽视了有边界的问题,导致解答错误。。。看来要么思考清楚,要么稳中求胜!不要刷小聪明!

其他:

  1. 关于 并查集 实现可以参考这里,大家的题解写的好认真啊(๑•̀ㅂ•́)و✧

二刷代码

这次使用的DFS更加地简单和明了:

//使用DFS进行求解,其实就是一个求连通分支的问题
class Solution {
public:
    int dir[4][4] = {{-1,0},{1,0},{0,-1},{0,1}};
    int cnt = 0;
    int m,n;
    vector<vector<bool>> vis;

    int numIslands(vector<vector<char>>& grid) {
        m = grid.size();
        if(m==0){
            return 0;
        }
        n = grid[0].size();

        vis.assign(m,vector<bool>(n,false));

        //开始奇幻的dfs之旅
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(judge(i,j,grid)){
                    dfs(i,j,grid);
                    cnt++;
                }
            }
        }
        return cnt;
    }

    void dfs(int x,int y,vector<vector<char>>& grid){
        vis[x][y] = true;

        for(int i=0;i<4;i++){
            int newX = x+dir[i][0];
            int newY = y+dir[i][1];
            if(judge(newX,newY,grid)){
                dfs(newX,newY,grid);
            }
        }
    }

    bool judge(int x,int y,vector<vector<char>>& grid){
        if(x<0||x>=m||y<0||y>=n){
            return false;
        }
        if(vis[x][y]==true){
            return false;
        }
        if(grid[x][y]=='0'){
            return false;
        }
        return true;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值