305. 岛屿数量 II
题目:
假设你设计一个游戏,用一个 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 的长度)
解答:
方法1:
首先我想到的就是dfs,每次加入陆地的时候考察一共有多少岛屿。但不能每次加入陆地都遍历全部矩阵,这样复杂度太高了,需要剪枝。
我的思路是这样:
每个独立的岛屿有独特的编号。每次addland的时候,遍历周边四个位置。
1.如果有一个相邻岛屿,岛屿数--,保存这个相邻岛屿的编号。
2.如果有第二个、甚至第三、四个相邻岛屿,就把之后的相邻的岛屿都用dfs遍历,全部更新为第一个相邻岛屿的编号。每次仍然记得总岛屿数--。
3.如果没有相邻岛屿,直接赋岛屿编号,全局的岛屿编号加一。
代码:
1 class Solution { 2 public: 3 vector<vector<int>> d={{0,-1},{0,1},{1,0},{-1,0}}; 4 int m,n; 5 bool check(int x,int y){ 6 if(x<0 or x>=m or y<0 or y>=n){ 7 return false; 8 } 9 return true; 10 } 11 vector<int> numIslands2(int m, int n, vector<vector<int>>& positions) { 12 this->m=m; 13 this->n=n; 14 vector<vector<int>> matrix(m,vector<int>(n,0)); 15 int val=1;//下一个有效的岛屿编号 16 vector<int>res(positions.size(),0); 17 res[0]=1; 18 matrix[positions[0][0]][positions[0][1]]=val++; 19 for(int i=1;i<positions.size();++i){ 20 if(matrix[positions[i][0]][positions[i][1]]!=0){//本身就是岛屿 21 res[i]=res[i-1]; 22 continue; 23 } 24 res[i]=res[i-1]+1; 25 int x=positions[i][0],y=positions[i][1],cur_val=0; 26 // cout<<"addland "<<x<<" "<<y<<endl; 27 for(int j=0;j<4;++j){ 28 int new_x=x+d[j][0],new_y=y+d[j][1]; 29 if(check(new_x,new_y) and matrix[new_x][new_y]!=cur_val){ 30 if(cur_val==0){//相邻的第一片岛屿 31 cur_val=matrix[new_x][new_y]; 32 res[i]--; 33 } 34 else if(matrix[new_x][new_y]!=0){//相邻的第二/三/四片岛屿 35 dfs(matrix,new_x,new_y,matrix[new_x][new_y],cur_val); 36 res[i]--; 37 } 38 } 39 } 40 matrix[x][y]=cur_val==0?val++:cur_val; 41 // for(auto& vec:matrix){ 42 // for(int x:vec){ 43 // cout<<x<<" "; 44 // }cout<<endl; 45 // } 46 } 47 return res; 48 } 49 50 void dfs(vector<vector<int>>& matrix,int x,int y,int ori_val,int new_val){ 51 // cout<<"dfs: "<<x<<" "<<y<<" "<<ori_val<<" "<<new_val<<endl; 52 //将ori_val改为new_val 53 matrix[x][y]=new_val; 54 int new_x,new_y; 55 for(int i=0;i<4;++i){ 56 new_x=x+d[i][0],new_y=y+d[i][1]; 57 if(check(new_x,new_y) and matrix[new_x][new_y]==ori_val){ 58 dfs(matrix,new_x,new_y,ori_val,new_val); 59 } 60 } 61 } 62 };

方法2:
使用并差集。
代码:
1 class Solution { 2 public: 3 vector<vector<int>> dif={{0,1},{0,-1},{1,0},{-1,0}}; 4 //并差集 5 vector<int> parents; 6 int islands = 0; 7 int getParent(int child){ 8 if(child!=parents[child]){ 9 parents[child]=getParent(parents[child]); 10 } 11 return parents[child]; 12 } 13 void merge(int x, int y){ 14 int px = getParent(x); 15 int py = getParent(y); 16 if(px != py){ 17 parents[px] = py; 18 islands--; 19 } 20 } 21 vector<int> numIslands2(int m, int n, vector<vector<int>>& positions) { 22 vector<int> res; 23 parents.assign(m*n,-1); 24 for(auto& coordinate:positions){ 25 int row=coordinate[0],col=coordinate[1],index=row*n+col; 26 if(parents[index]==-1){//水 27 ++islands; 28 parents[index]=index; 29 for(const auto& d:dif){ 30 int new_index=(row+d[0])*n+col+d[1]; 31 if(row+d[0]<m and row+d[0]>=0 and col+d[1]<n and col+d[1]>=0 and parents[new_index]!=-1){ 32 merge(new_index,index); 33 } 34 } 35 } 36 res.push_back(islands); 37 } 38 return res; 39 } 40 };


浙公网安备 33010602011771号