LeetCode 695. 岛屿的最大面积 && 广度|深度优先搜索

题目要求

原题目链接:695. 岛屿的最大面积

题目要求如下:
给你一个大小为 m x n 的二进制矩阵 grid 。

岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。

岛屿的面积是岛上值为 1 的单元格的数目。

计算并返回 grid 中最大的岛屿面积。如果没有岛屿,则返回面积为 0 。

示例如下:
在这里插入图片描述
输入:grid = [[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 。

解法1:深度优先搜索

思路

题目目的是求出网格中每块连通的面积,之后找出所有"岛屿"中面积最大的,并返回面积值。

那么我们只需要对网格|二维数组进行遍历,每次遍历到值为1的点时用计数器记录,并调用方法进行判断,寻找该点上下左右四个方向的点是否也为1,为1则计数器记录,同时再调用方法向下寻找四个方向的点并判断,以此类推。

为了避免数组内的点被重复访问,在记录过某一点面积后将该点的值修改为0即可,同时在代码书写过程中要注意边界情况处理。

完整AC代码

class Solution {
	// 定义两个数组 组合后与点坐标相加 可以得到点周围四个方向点的坐标
    int[] x = {0, 1, 0, -1};
    int[] y = {-1, 0, 1, 0};
    public int maxAreaOfIsland(int[][] grid) {
        int ans = 0;
        for(int i = 0; i < grid.length; i++){
            for(int j = 0; j <grid[0].length; j++){
            	// 每次都只记录最大面积
                ans = Math.max(ans, dfs(grid, i, j));
            }
        }
        return ans;
    }
    
    public int dfs(int[][]grid, int cx, int cy){
    	// 边界条件判断 以及01判断
        if(cx < 0 || cy < 0 || cx >= grid.length || cy >= grid[0].length || grid[cx][cy] == 0) return 0;
        int ans = 1;
        // 访问过的点不应该再次被访问 设为0避免重复访问
        grid[cx][cy] = 0;
        // 当前点的四个方向遍历 此处不需要判断坐标合规 因为df方法会判断
        for(int i = 0; i < 4; i++){
            ans += dfs(grid, cx + x[i], cy + y[i]);
        }
        return ans;
    }
}

复杂度分析

时间复杂度:O(R × C),其中R和C分别表示给定网格行列,网格中的每个点最多访问一次,故时间复杂度O(R × C)。
空间复杂度:O(R × C),判断并记录岛屿面积时需要递归,递归深度最坏的情况是整个二维数组值都为1,即需要整个网格递归,因此空间复杂度为O(R × C)。

解法2:广度优先搜索

思路

与DFS思路基本相同,唯一的区别在于DFS在取到一个点的值为1时,立即递归调用判断下一个点,直到某一个点四周点的值全部为0时才开始记录面积。而bfs在取到一个点的值为1时,先将四周的点加入到一个队列中(放到队尾),不立即进行四周点的判断记录工作,而是在完成自己的面积记录后才执行四周的点判断。

完整AC代码

class Solution {
    int[] x = {0, 1, 0, -1};
    int[] y = {-1, 0, 1, 0};
    public int maxAreaOfIsland(int[][] grid) {
        int ans = 0;
        for(int i = 0; i < grid.length; i++){
            for(int j = 0; j <grid[0].length; j++){
                int cnt = 0;
                Queue<Integer> qx = new LinkedList<Integer>();
                Queue<Integer> qy = new LinkedList<Integer>();
                qx.offer(i);
                qy.offer(j);
                while(!qx.isEmpty()){
                    int cx = qx.poll();
                    int cy = qy.poll();
                    if(cx < 0 || cy < 0 || cx >= grid.length || cy >= grid[0].length || grid[cx][cy] == 0) continue;
                    cnt++;
                    grid[cx][cy] = 0;
                    for(int k = 0; k < 4; k++){
                        qx.offer(cx + x[k]);
                        qy.offer(cy + y[k]);
                    }
                }

                ans = Math.max(ans, cnt);
            }
        }
        return ans;
    }
}

复杂度分析

时间复杂度:O(R × C),与DFS相同,其中R和C分别表示给定网格行列,网格中的每个点最多访问一次,故时间复杂度O(R × C)。
空间复杂度:O(R × C),需要额外的队列存放所有值为1的点,最坏的情况为R × C个点需要存储,故时间复杂度O(R × C)。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

7rulyL1ar

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值