【Warrior刷题笔记】LC1020.飞地的数量 【DFS】详细注释简单易懂

题目

LC1020.飞地的数量

解题思路

本题可以使用DFS解决。
遍历每个格子,如果该格子是陆地,就DFS该陆地所在的岛屿,并计算岛屿面积,并修改格子值为2防止重复遍历。在遍历过程中,只要有一块陆地在边界,这个岛屿就不是飞地,否则就是飞地。计算所有飞地面积之和,返回答案ans
dfs遍历求所有岛屿面积参考LC200.岛屿数量

class Solution {
private:
    constexpr static int direction[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};//方向辅助数组
public:
    int numIslands(vector<vector<char>>& grid) {
        int m = grid.size(), n = grid[0].size();//计算网格长宽
        function<void(int,int)> func = [&](int x, int y){//dfs
            grid[x][y] = '2';//修改值为2防止重复遍历
            for(const auto& [xOfs,yOfs] : direction){//对四个方向上是陆地的地方dfs
                int i = x + xOfs, j = y + yOfs;
                if(i>=0 && j>=0 && i<m && j<n && grid[i][j]=='1') func(i,j);
            }
        };
        int ans = 0;//存答案
        for(int k = 0; k < m; ++k){//遍历网格
            for(int z = 0; z < n; ++z){
                if(grid[k][z]=='1'){//遇到陆地岛屿数量就加一
                    ++ans;
                    func(k,z);//同时标记该岛屿所有陆地,防止重复遍历
                }
            }
        }
        return ans;//返回答案
    }
};

以及LC695岛屿的最大面积

class Solution {
private:
    constexpr static int direction[4][2] = { {-1,0},{1,0},{0,-1},{0,1} };//方向辅助数组
public:
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        int m = grid.size(), n = grid[0].size();//计算网格长宽
        int ans = 0, area = 0;//存答案,记录岛屿当前面积
        function<void(int, int)> func = [&](int x, int y) {//dfs
            grid[x][y] = 2;//每遍历一个陆地格子,将其值改为2防止重复遍历
            ++area;//当前岛屿面积加一
            for (const auto& [xOfs, yOfs] : direction) {//依次遍历四个方向上是陆地的格子
                int i = x + xOfs, j = y + yOfs;
                if (i >= 0 && j >= 0 && i < m && j < n && grid[i][j] == 1) func(i, j);
            }
        };
        for (int k = 0; k < m; ++k) {//依次遍历每个格子
            for (int z = 0; z < n; ++z) {
                if (grid[k][z] == 1) {//如果是陆地计算该陆地所在岛屿面积并标记
                    area = 0;
                    func(k, z);
                    if (area > ans) ans = area;//更新最大岛屿面积
                }
            }
        }
        return ans;//返回答案
    }
};

还有LC827.最大人工岛

class Solution {
    constexpr static int direction[4][2] = { {-1,0},{1,0},{0,-1},{0,1} };
public:
    int largestIsland(vector<vector<int>>& grid) {
        int m = grid.size(), n = grid[0].size();//计算网格长宽
        int ans = 0, area = 0;//存答案,记录各岛面积
        vector<pair<int, int>> areas;//存所有岛及其面积
        int count = 2;//岛屿标记

        //dfs函数
        function<void(int, int)> func = [&](int x, int y) {//dfs求岛屿面积
            grid[x][y] = count;//标记陆地的岛屿号
            ++area;//每遍历一块陆地,岛屿面积加一
            for (const auto& [xOfs, yOfs] : direction) {//依次从四个方向进行dfs
                int i = x + xOfs, j = y + yOfs;
                if (i >= 0 && j >= 0 && i < m && j < n && grid[i][j] == 1) func(i, j);
            }
        };

        bool isThereAWaterArea = false;//判断有没有水
        for (int k = 0; k < m; ++k) {
            for (int z = 0; z < n; ++z) {
                if (grid[k][z] == 1) {
                    area = 0;//初始化岛屿当前面积为0
                    func(k, z);//计算岛屿面积并进行陆地格子标记
                    areas.emplace_back(make_pair(count++, area));//将每个岛屿的标记-面积键值对压入数组
                }
                else if (grid[k][z] == 0) isThereAWaterArea = true;//有水则isThereAWaterArea = true
            }
        }
        if (!isThereAWaterArea) return m * n;//没水直接返回网格总面积
        if (areas.size() == 0) return 1;//没岛直接返回1
        if (areas.size() == 1) return ++area;//只有一个岛直接返回该岛面积加一
        for (int k = 0; k < m; ++k) {//依次遍历每个水域格子
            for (int z = 0; z < n; ++z) {
                if (grid[k][z] == 0) {
                    set<pair<int, int>> areasAround;//存储水域周边岛屿标记-面积键值对
                    //依次存入四周的岛屿
                    if (k > 0 && grid[k - 1][z] != 0) areasAround.emplace(areas[grid[k - 1][z] - 2]);
                    if (k < m - 1 && grid[k + 1][z] != 0) areasAround.emplace(areas[grid[k + 1][z] - 2]);
                    if (z > 0 && grid[k][z - 1] != 0) areasAround.emplace(areas[grid[k][z - 1] - 2]);
                    if (z < n - 1 && grid[k][z + 1] != 0) areasAround.emplace(areas[grid[k][z + 1] - 2]);
                    int areaTemp = 0;//四周岛屿面积总和,初始化为0
                    for (const auto& s : areasAround) areaTemp += s.second;
                    ans = ans < areaTemp ? areaTemp : ans;//更新最大人工岛面积
                }
            }
        }
        return ++ans;//返回答案,++是加上被填为陆地的水域格子
    }
};

代码

class Solution {
private:
    constexpr static int direction[4][2] = { {-1,0},{1,0},{0,-1},{0,1} };//方向辅助数组
public:
    int numEnclaves(vector<vector<int>>& grid) {
        int m = grid.size(), n = grid[0].size();//计算网格长宽
        int ans = 0, area = 0;//存答案,记录岛屿当前面积

        //dfs函数
        function<bool(int, int)> func = [&](int x, int y) {//dfs
            bool isAnEnclaves;
            if(x==0 || x==m-1 || y==0 || y==n-1) isAnEnclaves = false;//如果在边界,该陆地不是飞地
            else isAnEnclaves = true;
            grid[x][y] = 2;//每遍历一个陆地格子,将其值改为2防止重复遍历
            ++area;//当前岛屿面积加一
            for (const auto& [xOfs, yOfs] : direction) {//依次遍历四个方向上是陆地的格子
                int i = x + xOfs, j = y + yOfs;
                if (i >= 0 && j >= 0 && i < m && j < n && grid[i][j] == 1){
                    if(!func(i, j)) isAnEnclaves = false;//只要岛屿中有一块陆地不是飞地,则整个岛屿都不是飞地
                }
            }
            return isAnEnclaves;
        };

        for (int k = 0; k < m; ++k) {//依次遍历每个格子
            for (int z = 0; z < n; ++z) {
                if (grid[k][z] == 1) {//如果是陆地计算该陆地所在岛屿面积并标记
                    area = 0;
                    if(func(k, z)) ans += area;//累加飞地面积
                }
            }
        }
        return ans;//返回答案
    }
};

复杂度分析

时间复杂度: O(mn)m,n分别为网格长宽,需要遍历每个格子一次。
空间复杂度: O(log(max(m,n))。递归栈的空间消耗。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值