​LeetCode刷题实战305:岛屿数量II

算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试。所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 !

今天和大家聊的问题叫做 岛屿数量II,我们先来看题面:

https://leetcode-cn.com/problems/number-of-islands-ii/

A 2d grid map of m rows and n columns is initially filled with water. We may perform an addLand operation which turns the water at position (row, col) into a land. Given a list of positions to operate, count the number of islands after each addLand operation. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.

假设你设计一个游戏,用一个 m 行 n 列的 2D 网格来存储你的游戏地图。

起始的时候,每个格子的地形都被默认标记为「水」。我们可以通过使用 addLand 进行操作,将位置 (row, col) 的「水」变成「陆地」。

你将会被给定一个列表,来记录所有需要被操作的位置,然后你需要返回计算出来 每次 addLand 操作后岛屿的数量。

注意:一个岛的定义是被「水」包围的「陆地」,通过水平方向或者垂直方向上相邻的陆地连接而成。你可以假设地图网格的四边均被无边无际的「水」所包围。

请仔细阅读下方示例与解析,更加深入了解岛屿的判定。

示例

示例:
输入: m = 3, n = 3, 
  positions = [[0,0], [0,1], [1,2], [2,1]]
输出: [1,1,2,3]
解析:
起初,二维网格 grid 被全部注入「水」。(0 代表「水」,1 代表「陆地」)
0 0 0
0 0 0
0 0 0

操作 #1:addLand(0, 0) 将 grid[0][0] 的水变为陆地。
1 0 0
0 0 0 Number of islands = 1
0 0 0

操作 #2:addLand(0, 1) 将 grid[0][1] 的水变为陆地。
1 1 0
0 0 0 岛屿的数量为 1
0 0 0

操作 #3:addLand(1, 2) 将 grid[1][2] 的水变为陆地。
1 1 0
0 0 1 岛屿的数量为 2
0 0 0

操作 #4:addLand(2, 1) 将 grid[2][1] 的水变为陆地。
1 1 0
0 0 1 岛屿的数量为 3
0 1 0

拓展:
你是否能在 O(k log mn) 的时间复杂度程度内完成每次的计算?
(k 表示 positions 的长度)

解题

https://blog.csdn.net/weixin_44171872/article/details/109906933

主要思路:

(1)将每种岛屿使用一种正整数进行标识;

(2)当新插入的位置只和原有的一个岛屿相邻,则将新插入的位置也标识为该岛屿的标识;

(3)当新插入的位置造成两个及两个以上的岛屿连接到一起,则使用其中的一个岛屿的标识来标识该位置,并同时将其余几个相邻的岛屿的标识也修改成这个相同的标识,是新形成的岛屿使用同一个数字进行标识;

(4)至于新插入的位置之后获得的岛屿的数量,则根据上述的情形进行分类处理即可,具体见代码;

class Solution {
public:
  //主要用于将给定的岛屿使用新的数字进行标识
    void dfs(vector<vector<int>>& mp,const int& cur_index,int old_index,pair<int,int> cur_pos){
        if(mp[cur_pos.first][cur_pos.second]!=old_index){//说明当前位置不是要修改的岛屿的位置
            return;
        }
        mp[cur_pos.first][cur_pos.second]=cur_index;//将岛屿的标识修改为新的数字
        //对相邻的位置进行判断
        if(cur_pos.first>0){
            dfs(mp,cur_index,old_index,{cur_pos.first-1,cur_pos.second});
        }
        if(cur_pos.first<mp.size()-1){
            dfs(mp,cur_index,old_index,{cur_pos.first+1,cur_pos.second});
        }
        if(cur_pos.second>0){
            dfs(mp,cur_index,old_index,{cur_pos.first,cur_pos.second-1});
        }
        if(cur_pos.second<mp[0].size()-1){
            dfs(mp,cur_index,old_index,{cur_pos.first,cur_pos.second+1});
        }
    }
    vector<int> numIslands2(int m, int n, vector<vector<int>>& positions) {
        vector<vector<int>> mp(m,vector<int>(n,0));//整个水域
        vector<int> res(positions.size(),0);//统计每次插入后造成的岛屿的数量
        //插入
        for(int i=0;i<positions.size();++i){
            unordered_map<int,pair<int,int>> st;//统计当前插入位置处可能的相邻的岛屿
            //当前插入的位置
            int row=positions[i][0];
            int col=positions[i][1];
            if(mp[row][col]!=0){//避免重复的插入
                res[i]=res[i-1];
                continue;
            }
            //判断各个相邻的位置是否是岛屿
            if(row>0&&mp[row-1][col]!=0){
                st[mp[row-1][col]]={row-1,col};
            }
            if(row<m-1&&mp[row+1][col]!=0){
                st[mp[row+1][col]]={row+1,col};
            }
            if(col>0&&mp[row][col-1]!=0){
                st[mp[row][col-1]]={row,col-1};
            }
            if(col<n-1&&mp[row][col+1]!=0){
                st[mp[row][col+1]]={row,col+1};
            }
            //若当前位置没有相邻的岛屿
            if(st.empty()){
                mp[row][col]=i+1;//标识当前岛屿
                //处理特殊的情形
                if(i==0){
                    res[i]=1;
                }
                else{
                    res[i]=res[i-1]+1;//新增一个岛屿,既在之前岛屿数量基础上,新增一个岛屿
                }
            }
            else if(st.size()==1){//若新插入的位置只和一个岛屿相邻
              //将当前位置和相邻的岛屿使用相同的数字进行标识
                mp[row][col]=st.begin()->first;
                res[i]=res[i-1];//说明没有造成新增岛屿,故和之前岛屿数量相同
            }
            else{//相邻的岛屿的数量大于一个
              //在相邻的岛屿中选择一个,使用其数字作为标识
                int cur_index=st.begin()->first;
                mp[row][col]=cur_index;//使用岛屿的数字标识当前位置
                res[i]=res[i-1]-st.size()+1;//由于合并了一些岛屿,故需要根据相邻的岛屿的数量进行标识
                for(auto& it:st){//将其他几个岛屿的表示数字也修改为相同的标识数字,来标识是同一个新的岛屿
                    if(it.first!=cur_index){
                        dfs(mp,cur_index,mp[it.second.first][it.second.second],it.second);
                    }
                }
            }
        }
        return res;
    }
};

好了,今天的文章就到这里,如果觉得有所收获,请顺手点个在看或者转发吧,你们的支持是我最大的动力 。

上期推文:

LeetCode1-280题汇总,希望对你有点帮助!

LeetCode刷题实战301:删除无效的括号

LeetCode刷题实战302:包含全部黑色像素的最小矩阵

LeetCode刷题实战303:区域和检索 - 数组不可变

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值