矩阵类dfs

て烟熏妆下的殇ゞ 提交于 2020-01-27 01:33:07

dfs即深度优先搜索,正如名字所说,其是一种搜索方式,按照深度进行逐个搜索,dfs常用于回溯算法中,两者十分相似,只是,回溯法是实现方法,深度优先搜索是实现方式,同时在树的相关搜索中也会出现深度优先搜索方式,基本思想和回溯算法类似,不过有个最大不同点是回溯法需要在有回溯过程,而dfs不需要回溯,其只需向着满足条件大方向搜索,直到不满足条件为止。这里不再详细讲解算法的定义等理解性的东西,而是通过分析几个例题,得出解这类题目的模板。

岛屿数量

给定一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。

输入:
11110
11010
11000
00000
输出: 1

输入:
11000
11000
00100
00011
输出: 3

很明显该题是搜索类的问题,而且不需要把每一项都枚举出来,因此可考虑dfs,特别是矩阵类的dfs,套路很固定,首先,需要定义四个方向,即每个位置的上下左右,对每个方向都进行判断是否满足继续向下搜索的条件,如果满足,那么就调用dfs递归函数进行递归调用,同时在进行每个方向选择时需要注意下个位置是否已经遍历过,因此,一般会需要一个额外的数组来存储某个位置是否已经被调用过,不过这道题显然可以不是使用额外数组,直接在原数组上将遍历过的数据置为0即可为了统计数量,需要在遍历开始时,对岛屿数量加一,代表这次遍历会经过属于该块岛屿的所有块,看懂解题思想后代码就很好实现了。

class Solution {
private:
//定义四个方向,上下左右,方向的顺序排列没有影响
    vector<vector<int>>dir={{1,0},{-1,0},{0,1},{0,-1}};
public:
//定义dfs递归函数
    void dfs(vector<vector<char>>& grid,int x,int y){
    //遍历过该位置后将该位置置为0,代表该位置已经遍历过
        grid[x][y]='0';
    //对矩阵的四个方向进行搜索
        for(int k=0;k<4;++k){
            int xx=x+dir[k][0];
            int yy=y+dir[k][1];
           	//判断下一个方向的位置是否满足继续向下搜索的条件,如果满足就继续对下一位置进行dfs调用
            if(xx>=0 && xx<grid.size() && yy>=0 && yy<grid[0].size() && grid[xx][yy]=='1'){
                dfs(grid,xx,yy);
            }
        }
        //注意该处没有采用撤销该选择的步骤,即回溯法中必须要有的步骤
    }
    int numIslands(vector<vector<char>>& grid) {
        int rows=grid.size();
        if(rows==0)return 0;
        int cols=grid[0].size();
        int res=0;
        //对每个位置进行遍历,如果该位置为1,那么岛屿数就加1,并调用dfs函数,代表将属于该岛屿的1全部遍历并置为0
        for(int i=0;i<rows;++i){
            for(int j=0;j<cols;++j){
                if(grid[i][j]=='1'){
                    ++res;
                    dfs(grid,i,j);
                }
            }
        }
        return res;
    }
};

做过回溯法题的人应该对改代码比较熟悉,不同点在于,在遍历过四个方向后,不需要撤销刚遍历过的路径。
将该题稍加变形就成为下一道题

岛屿的最大面积

给定一个包含了一些 0 和 1的非空二维数组 grid , 一个 岛屿 是由四个方向 (水平或垂直) 的 1 (代表土地) 构成的组合。你可以假设二维矩阵的四个边缘都被水包围着。
找到给定的二维数组中最大的岛屿面积。(如果没有岛屿,则返回面积为0。)

[[0,0,1,0,0,0,0,1,0,0,0,0,0],
[0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,1,1,0,1,0,0,0,0,0,0,0,0],
[0,1,0,0,1,1,0,0,1,0,1,0,0],
[0,1,0,0,1,1,0,0,1,1,1,0,0],
[0,0,0,0,0,0,0,0,0,0,1,0,0],
[0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,0,0,0,0,0,0,1,1,0,0,0,0]]
对于上面这个给定矩阵应返回 6。注意答案不应该是11,因为岛屿只能包含水平或垂直的四个方向的‘1’。

十分类似的题目,仍然需要定义四个方向,判断某位置是否已经遍历过,不过由于解题的目标不一样,所以有些地方需要改变,这里需要在进行判断满足继续遍历条件后,将该位置的四个方向的岛屿数量相加,即可得到该位置对应的岛屿面积,在每次遍历后找到最大的岛屿面积即可。

class Solution {
private:
    vector<vector<int>>dir={{1,0},{-1,0},{0,1},{0,-1}};
public:
    int dfs(vector<vector<int>>& grid,int x,int y){
    //需要定义该位置的岛屿面积为1
        int ans=1;
        grid[x][y]=0;
        for(int k=0;k<4;++k){
            int xx=x+dir[k][0];
            int yy=y+dir[k][1];
            if(xx>=0 && xx<grid.size() && yy>=0 && yy<grid[0].size() && grid[xx][yy]==1){
            //将该位置和其四周的岛屿面积相加得到该位置的岛屿面积
                ans+=dfs(grid,xx,yy);
            }
        }
        return ans;
    }
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        int rows=grid.size();
        if(rows==0)return 0;
        int cols=grid[0].size();
        int res=0;
        for(int i=0;i<rows;++i){
            for(int j=0;j<cols;++j){
                if(grid[i][j]==1){
                //便利的到每块岛屿的面积,并比较大小得出最大岛屿面积
                    int temp=dfs(grid,i,j);
                    res=max(res,temp);
                }
            }
        }
        return res;
    }
};
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!