(岛屿问题一) leetcode 695: 岛屿的最大面积

leetcode 695: 岛屿的最大面积

题目描述

给定一个包含了一些 0 和 1 的非空二维数组 grid 。
一个 岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在水平或者竖直方向上相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。
找到给定的二维数组中最大的岛屿面积。(如果没有岛屿,则返回面积为 0 。)
示例一:

Input:[[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]]
Output: 6

示例二:

Input:[[0,0,0,0,0,0,0,0]]
Output: 0

解题思路

根据题目描述,给定一个包含了一些 0 0 0 1 1 1 的非空二维数组 g r i d grid grid,一个岛屿是由四个方向(水平或者垂直)的 1 1 1 (代表土地)构成的组合。
题目要找岛屿的最大面积,但是不知道如果才能测量出岛屿的最大面积,所以为了测量整个岛屿的面积,只能采取一步步探索的方式。可以看出,这是一道标准的搜索题。今天先以深度优先搜索进行说明,宽度优先搜索后续再加上。
深度优先搜索思路具体如下:
当到达某个位置时,以此所处位置为行动中心,分别向上下左右四个方向进行前进。如果向某一方向前进后发现其不是陆地或者已经被搜索过,则停止搜索;如果向某一方向前进后发现其是陆地,则以扩展后的所处位置为新的行动中心,再向上下左右四个方向进行前进。以此类推。

深度优先搜索代码实现说明

深度优先搜索在搜索到一个节点时,立即对该新节点进行遍历,**因此遍历时需要采用先入后出的栈或者与栈进行等价的递归来实现。**由于递归相对便于实现,因此刷题时建议用递归进行写。
一般来说,深度优先搜索的标准写法: 深度优先搜索的题分为主函数和辅函数,主函数用于遍历所有的搜索位置,判断是否开始搜索,如果开始即在辅函数中进行搜索。辅函数则负责深度优先搜索的递归调用。 辅函数的写法:在辅函数里,一定有一个要注意的点是辅函数内递归搜索时,边界条件的判定。边界条件一般有两种写法: 一是先判断是否越界,只有在合法的情况下才进行下一步搜索(即判断放在递归函数前);另一种是先进行下一步搜索,在下一步搜索开始时再判断是否合理,判断一般放在辅函数第一行。 这两种写法都可以,根据个人习惯进行选择,一般我选择用后者去写。

题解

根据上述深度优先搜索代码实现说明,首先在主函数中遍历所有位置,如果满足条件进入辅函数。

int maxAreaOfIsland(vector<vector<int> > & grid)
{
    int m = grid.size();
    int n = grid[0].size();
    if(m == 0 || n == 0) return 0;
    for(int i=0; i<m; ++i)
    {
        for(int j=0; j<n; ++j)
        {
            if(grid[i][j] == 1)
            {
                dfs(grid, i, j, count);
            }
        }
    }
}

在辅函数中,根据辅函数第二种写法,不管三七二十一先进行递归,然后在每次递归刚进来的时候进行条件判断。如果不满足条件则直接 r e t u r n return return,满足条件再进行处理。
处理需要实现的是:由于统计岛屿最大面积,因此每次判断扩展后的区域是陆地后,将统计个数的变量加1,同时为了防止重复遍历该位置,将其位置的值进行更改,从而避免重复遍历。
辅函数如下:

vector<int> direction{-1, 0, 1, 0, -1};
void dfs(vector<vector<int> > & grid, int i, int j, int & count)
{
    if(i < 0 || i >= grid.size() || j<0 || j>= grid[0].size() || grid[i][j] == 0)
    {
        return;
    }
    grid[i][j] = 0;
    count++;
    for(int dk = 0; dk<4; ++dk)
    {
        int x = i + direction[dk];
        int y = j + direction[dk+1];
        dfs(grid, x, y, count);
    }
}

这里有一个小技巧,以后写的时候都用这种写法: 对于四个方向的遍历,可以创建一个数组 d i r e c t i o n = [ − 1 , 0 , 1 , 0 , − 1 ] direction = [-1, 0, 1, 0, -1] direction=[1,0,1,0,1],每相邻两位即为上下左右四个方向之一。
整个代码如下:

int maxAreaOfIsland(vector<vector<int> > & grid)
{
    int m = grid.size();
    int n = grid[0].size();
    int result = 0;
    if(m == 0 || n == 0) return 0;
    for(int i=0; i<m; ++i)
    {
        for(int j=0; j<n; ++j)
        {
            if(grid[i][j] == 1)
            {
                int count = 0;
                dfs(grid, i, j, count);
                if(count > result)
                {
                    result = count;
                }
            }
        }
    }
    return result;
}
vector<int> direction{-1, 0, 1, 0, -1};
void dfs(vector<vector<int> > & grid, int i, int j, int & count)
{
    if(i < 0 || i >= grid.size() || j<0 || j>= grid[0].size() || grid[i][j] == 0)
    {
        return;
    }
    grid[i][j] = 0;
    count++;
    for(int dk = 0; dk<4; ++dk)
    {
        int x = i + direction[dk];
        int y = j + direction[dk+1];
        dfs(grid, x, y, count);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值