算法入门 05深度优先搜索(中等 - 第一题)LeetCode 695

Posted 英雄哪里出来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法入门 05深度优先搜索(中等 - 第一题)LeetCode 695相关的知识,希望对你有一定的参考价值。

🙉饭不食,水不饮,题必须刷🙉

还不会C语言,和我一起打卡!
🌞《光天化日学C语言》🌞

LeetCode 太难?上简单题!
🧡《C语言入门100例》🧡

LeetCode 太简单?大神盘他!
🌌《夜深人静写算法》🌌

一、题目

1、题目描述

  给定一个包含了一些 0 和 1 的非空二维数组 g r i d grid grid 。一个 岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在水平或者竖直方向上相邻。你可以假设 g r i d grid grid 的四个边缘都被 0(代表水)包围着。找到给定的二维数组中最大的岛屿面积。
  样例1: [ [ 1 , 0 , 1 ] , [ 1 , 1 , 1 ] , [ 0 , 0 , 1 ] ] [[1,0,1],[1,1,1],[0,0,1]] [[1,0,1],[1,1,1],[0,0,1]],输出 6 6 6
  样例2: [ [ 1 , 0 , 1 ] , [ 0 , 1 , 0 ] , [ 0 , 0 , 1 ] ] [[1,0,1],[0,1,0],[0,0,1]] [[1,0,1],[0,1,0],[0,0,1]],输出 1 1 1

2、基础框架

  • c++ 版本给出的基础框架代码如下,定义一个函数maxAreaOfIsland,函数的参数是一个vector的嵌套,代表的是一个二维数组;
  • vector<vector<int>>可以理解成vector<T>,其中T代表vector的元素,并且这个元素是另一个vector<int>。当然,可以嵌套的实现三维数组,甚至更高维的数组。
class Solution {
public:
    int maxAreaOfIsland(vector<vector<int>>& grid) {
    }
};

3、原题链接

LeetCode 695. 岛屿的最大面积

二、解题报告

1、思路分析

  • g r i d grid grid 中的每个 1 抽象成一个节点,且都有一个唯一编号。两个水平或者垂直方向相邻且都为 1,则在这两个节点之间连接一条无向边。举个例子:
  • [ 1 0 0 1 1 1 0 1 0 1 1 1 ] \\left[ \\begin{matrix} 1 & 0 & 0 & 1 \\\\ 1 & 1 & 0 & 1 \\\\ 0 & 1 & 1 & 1 \\end{matrix} \\right] 110011001111
  • 先将每个 1 的位置都分配一个编号,假设行号为 i i i,列号为 j j j,则它的编号就是 i × 4 + j i \\times 4 + j i×4+j,其中 4 4 4 代表总共有多少列。如下:
  • [ 0 E E 3 4 5 E 7 E 9 10 11 ] \\left[ \\begin{matrix} 0 & E & E & 3 \\\\ 4 & 5 & E & 7 \\\\ E & 9 & 10 & 11 \\end{matrix} \\right] 04EE59EE103711
  • E E E 的含义是 Empty 的意思,可以用一个额外的编号(不和其它现有编号冲突)表示,比如 -1。
  • 所以,它其实应该是这样一个图:
  • 这样,我们就可以转换成用深度优先搜索来求连通块问题了。
  • 关于深度优先搜索的更深入内容,可以参考这篇文章:夜深人静写算法(一)- 搜索入门

2、时间复杂度

  • 由于有哈希数组在,所以 g r i d grid grid 的每个元素最多被访问一次,如果长 n n n 宽为 m m m g r i d grid grid,时间复杂度为 O ( n m ) O(nm) O(nm)

3、代码详解

const int dir[4][2] = { {0, 1}, {0, -1}, {1, 0}, {-1, 0} };           // (1)
int bHash[100][100];                                                  // (2)
int n, m;                                                             // (3)

class Solution {
public:
    void dfs(vector<vector<int>>& grid, int &count, int x, int y) {   // (4)
        if(x < 0 || y < 0 || x >= n || y >= m) {
            return ;                                                  // (5)
        }
        if(!grid[x][y]) {
            return ;                                                  // (6)
        }

        if(bHash[x][y]) {
            return;                                                   // (7)
        }
        bHash[x][y] = 1;
        ++count;

        for(int i = 0; i < 4; ++i) {
            dfs(grid, count, x + dir[i][0], y + dir[i][1]);           // (8)
        }
    }

    int maxAreaOfIsland(vector<vector<int>>& grid) {
        n = grid.size();
        m = grid[0].size();
        memset(bHash, 0, sizeof(bHash));

        int count = 0, maxv = 0;
        for(int i = 0; i < n; ++i) {
            for(int j = 0; j < m; ++j) {
                if(grid[i][j] && !bHash[i][j]) {                      // (9)
                        count = 0;
                        dfs(grid, count, i, j);
                        maxv = max(maxv, count);                      // (10)
                    }
                }
            }
        }
        return maxv;
    }
};
  • ( 1 ) (1) (1) 代表四个方向的全局向量;
  • ( 2 ) (2) (2) 二维的哈希数组,用来标记一个位置有没有被访问过;
  • ( 3 ) (3) (3) 全局缓存 g r i d grid grid 的宽 和 高;
  • ( 4 ) (4) (4) 用于对全局进行搜素的递归函数,grid作为引用传参提高效率,count作为引用传参是当全局变量来用的,x,y代表的是当前枚举到的 行 和 列。
  • ( 5 ) (5) (5) 如果遇到搜索到边界的情况,终止搜索;
  • ( 6 ) (6) (6) 如果遇到不是岛屿的情况,终止搜索;
  • ( 7 ) (7) (7) 如果遇到已经搜索过的岛屿,终止搜索;否则,标记(x,y)被搜索过,且计数器count自增。
  • ( 8 ) (8) (8) 继续枚举四方向的下一个位置;
  • ( 9 ) (9) (9) grid的每个位置未被访问过(!bHash[i][j])的岛屿(grid[i][j])都必须枚举到;
  • ( 10 ) (10) (10) 取最大的连通块,max为系统库函数;

三、本题小知识

利用深度优先搜索,可以用来求图的连通块问题。


以上是关于算法入门 05深度优先搜索(中等 - 第一题)LeetCode 695的主要内容,如果未能解决你的问题,请参考以下文章

算法入门广度优先搜索(中等 - 第一题)LeetCode 994

算法入门深度优先搜索(中等 - 第二题)LeetCode 46

算法入门广度优先搜索(简单 - 第一题)LeetCode 542

每日一题 分割回文串(深度优先搜索)

算法入门 04模拟(中等 - 第一题)LeetCode 8

算法入门线性枚举(中等 - 第一题)LeetCode 19