算法学习笔记——专题拓展4:DFS 算法解决岛屿题目

例题1:二维数组的岛屿问题

例题1.1:岛屿数量

分析:标准的dfs框架, 每遇到一个‘1’,都用dfs去淹没这个岛屿。

用dfs淹没岛屿,就不需要维护visited了,因为只要进入岛屿的其他块,因为被淹没了,直接判断grid[i][j] 为0,效果和visited是一样的。

代码

class Solution {
public:
    int m, n;
    void dfs(vector<vector<char>>& grid,int i, int j){
        if(i < 0 || j < 0|| i>= m || j>= n){
            return;
        }
        if(grid[i][j] == '0'){
            return;
        }
        grid[i][j] = '0';
        dfs(grid, i+1, j);
        dfs(grid, i, j+1);
        dfs(grid, i-1, j);
        dfs(grid, i, j-1);
    }
    int numIslands(vector<vector<char>>& grid) {
        m =  grid.size();
        n = grid[0].size();
        int ret = 0;
        for(int i = 0; i< m; i++){
            for(int j = 0; j< n; j++){
                if(grid[i][j] == '1'){
                    ret++;
                    dfs(grid, i, j);
                }
            }
        }
        return ret;
    }
};

例题1.2:统计封闭岛屿的数目

分析:和例题1基本相同,只需要加一个判断量,看看每一次淹没岛屿有没有触及到边界即可。

代码

class Solution {
public:
    int nums = 0;
    int m, n;
    bool ReachBorder = false;
    void dfs(vector<vector<int>>& grid, int i, int j){
        if(i < 0 || j<0 || i>=m || j >= n){
            ReachBorder = true;
            return;
        }
        if(grid[i][j] == 1){
            return;
        }
        grid[i][j] = 1;
        dfs(grid, i+1, j);
        dfs(grid, i, j+1);
        dfs(grid, i-1, j);
        dfs(grid, i, j-1);
    }
    int closedIsland(vector<vector<int>>& grid) {
        m = grid.size(); n = grid[0].size();
        for(int i = 0; i< m; i++){
            for(int j = 0; j< n; j++){
                if(grid[i][j] == 0){
                    ReachBorder = false;
                    nums++;
                    dfs(grid, i, j);
                    if(ReachBorder){
                        nums--;
                    }
                }
            }
        }
        return nums;
    }
};

例题1.3:飞地的数量

分析:和例题2差不多,区别在于每次淹没岛屿需要计数岛屿的大小,淹没完成后,如果没有触及边界才加上去。

代码

class Solution {
public:
    int nums, m, n;
    int cnt;
    bool reachBorder;
    void dfs(vector<vector<int>>& grid, int i , int j){
        if(i < 0 || j<0 || i>= m|| j>=n){
            reachBorder = true;
            return;
        }
        if(grid[i][j] == 0){
            return;
        }
        grid[i][j] = 0;
        cnt++;
        dfs(grid, i+1, j);dfs(grid, i, j+1);dfs(grid, i-1, j);dfs(grid, i, j-1);
    }
    int numEnclaves(vector<vector<int>>& grid) {
        m = grid.size(); n = grid[0].size();
        for(int i = 0; i< m; i++){
            for(int j = 0; j <n ; j++){
                if(grid[i][j] == 1){
                    cnt = 0;reachBorder = false;
                    dfs(grid, i, j);
                    if(!reachBorder){
                        nums += cnt;
                    }
                }
            }
        }
        return nums;
    }
};

例题1.4:岛屿的最大面积

分析:和例题

代码

class Solution {
public:
    int best, cnt;
    int m, n;
    void dfs(vector<vector<int>>& grid, int i, int j){
        if(i<0||j<0||i>=m||j>=n){
            return;
        }
        if(grid[i][j] == 0){
            return;
        }
        grid[i][j] = 0;
        cnt++;
        dfs(grid, i+1, j);
        dfs(grid, i-1, j);
        dfs(grid, i, j+1);
        dfs(grid, i, j-1);
    }
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        m = grid.size(); n = grid[0].size();
        for(int i = 0; i< m; i++){
            for(int j = 0; j<n; j++){
                if(grid[i][j] == 1){
                    cnt = 0;
                    dfs(grid, i, j);
                    if(cnt > best){
                        best = cnt;
                    }
                }
            }
        }
        return best;
    }
};

例题2:统计子岛屿

分析

遍历grid2里面的每一个岛屿,只要对应的grid1格子都是陆地,它就一定是子岛屿。

代码

class Solution {
public:
    int m, n;
    int isSub;
    int ans = 0;
    void dfs(vector<vector<int>>& grid1, vector<vector<int>>& grid2, int i, int j){
        if (i<0 || j<0 || i>=m || j>= n){
            return;
        }
        if(grid2[i][j] == 0){
            return;
        }
        if(grid1[i][j] == 0){
            isSub = 0;
        }
        grid2[i][j] = 0;
        dfs(grid1, grid2, i+1, j);
        dfs(grid1, grid2, i-1, j);
        dfs(grid1, grid2, i, j+1);
        dfs(grid1, grid2, i, j-1);
    }
    int countSubIslands(vector<vector<int>>& grid1, vector<vector<int>>& grid2) {
        m = grid1.size(); n = grid1[0].size();
        for(int i  = 0; i< m; i++){
            for(int j = 0; j< n; j++){
                if(grid2[i][j] == 1){
                    isSub = 1;
                    dfs(grid1, grid2, i, j);
                    if(isSub == 1){
                        ans++;
                    }
                }
            }
        }
        return ans;
    }
};

.

例题3:岛屿的周长

分析

修改grid的值来代替visit数组

代码

class Solution {
public:
    int m, n;
    int ans = 0;
    void dfs(vector<vector<int>>& grid, int i, int j){
        if(i<0 || j<0 || i>= m|| j>= n || grid[i][j] == 0){
            ans++;
            return;
        }
        if(grid[i][j] == 2){
            return;
        }
        grid[i][j] = 2;
        dfs(grid, i+1, j);
        dfs(grid, i-1, j);
        dfs(grid, i, j+1);
        dfs(grid, i, j-1);
    }
    int islandPerimeter(vector<vector<int>>& grid) {
        m = grid.size(); n = grid[0].size();
        for(int i = 0; i< m; i++){
            for(int j  = 0; j< n; j++){
                if(grid[i][j] == 1){
                    dfs(grid, i, j);
                    break;
                }
            }
        }
        return ans;
    }
};

例题4:被围绕的区域

分析:

代码:

class Solution {
public:
    bool isSurrounded = true;
    int m, n;
    void dfs(vector<vector<char>>& board, int i, int j, int mode){
        if(i<0 || j<0 || i>=m || j>= n){
            isSurrounded = false;
            return;
        }
        switch(mode){
            case 0: if(board[i][j] == 'X' || board[i][j] == 'O'){
                        return;
                    }
                    board[i][j] = 'O';
                    break;
            case 1: if(board[i][j] == 'X' || board[i][j] == 'V'){
                        return;
                    }
                    board[i][j] = 'V';
                    break;
            case 2: if(board[i][j] == 'X'){
                        return;
                    }
                    board[i][j] = 'X';
                    break;
        }
        dfs(board, i+1, j, mode);
        dfs(board, i-1, j, mode);
        dfs(board, i, j+1, mode);
        dfs(board, i, j-1, mode);
    }

    void solve(vector<vector<char>>& board) {
        m = board.size(); n = board[0].size();
        for(int i  = 0; i< m; i++){
            for(int j = 0 ; j< n; j++){
                if(board[i][j] == 'O'){
                    isSurrounded = true;
                    dfs(board, i, j, 1);
                    if(isSurrounded){
                        dfs(board, i, j, 2);
                    }
                    else{
                        dfs(board, i, j, 0);
                    }
                }
            }
        }    
    }
};

总结

i)淹没岛屿的作用是,不需要维护visited数组

ii)框架:

在主函数里,遍历每个块,每当遇到一个大陆,就用dfs去淹没它;dfs里,如果越界或者已经访问过这个块,直接返回,否则,递归访问它的相邻块。

维护一个全局变量,dfs的函数里面对它做出更新,然后在主函数返回。

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值