给定一个布尔2D矩阵,找到孤岛的数量。
一组相连的1组成一个岛。例如,下面的矩阵包含5个岛
{1, 1, 0, 0, 0},
{0, 1, 0, 0, 1},
{1, 0, 0, 1, 1},
{0, 0, 0, 0, 0},
{1, 0, 1, 0, 1}
2D矩阵中的一个单元可以连接到8个邻居。
这是标准问题的一个变体:“计算无向图中的已连接组件数”。我们已经在下面的第1组中讨论了基于DFS的解决方案。
找出孤岛的数量
我们还可以使用此处说明的不相交集数据结构来解决该问题。想法是将所有1个值都视为单独的集合。遍历矩阵并对所有相邻的1个顶点进行并集。以下是详细步骤。
方法:
1)初始化结果(孤岛数)为0
2)遍历2D矩阵的每个索引。
3)如果该索引的值为1,请检查其所有8个邻居。如果邻居也等于1,则取索引及其邻居的并集。
4)现在定义一个大小为row * column的数组,以存储所有集合的频率。
5)现在再次遍历矩阵。
6)如果索引处的值为1,则找到它的集合。
7)如果上述数组中集合的频率为0,则将结果加1。
以下是上述步骤的Java实现。
C++
// C++ program to fnd number of islands
// using Disjoint Set data structure.
#include
using namespace std;
// Class to represent
// Disjoint Set Data structure
class DisjointUnionSets
{
vector rank, parent;
int n;
public:
DisjointUnionSets(int n)
{
rank.resize(n);
parent.resize(n);
this->n = n;
makeSet();
}
void makeSet()
{
// Initially, all elements
// are in their own set.
for (int i = 0; i < n; i++)
parent[i] = i;
}
// Finds the representative of the set
// that x is an element of
int find(int x)
{
if (parent[x] != x)
{
// if x is not the parent of itself,
// then x is not the representative of
// its set.
// so we recursively call Find on its parent
// and move i's node directly under the
// representative of this set
return find(parent[x]);
}
return x;
}
// Unites the set that includes x and the set
// that includes y
void Union(int x, int y)
{
// Find the representatives(or the root nodes)
// for x an y
int xRoot = find(x);
int yRoot = find(y);
// Elements are in the same set,
// no need to unite anything.
if (xRoot == yRoot)
return;
// If x's rank is less than y's rank
// Then move x under y so that
// depth of tree remains less
if (rank[xRoot] < rank[yRoot])
parent[xRoot] = yRoot;
// Else if y's rank is less than x's rank
// Then move y under x so that depth of tree
// remains less
else if (rank[yRoot] < rank[xRoot])
parent[yRoot] = xRoot;
else // Else if their ranks are the same
{
// Then move y under x (doesn't matter
// which one goes where)
parent[yRoot] = xRoot;
// And increment the result tree's
// rank by 1
rank[xRoot] = rank[xRoot] + 1;
}
}
};
// Returns number of islands in a[][]
int countIslands(vector>a)
{
int n = a.size();
int m = a[0].size();
DisjointUnionSets *dus = new DisjointUnionSets(n * m);
/* The following loop checks for its neighbours
and unites the indexes if both are 1. */
for (int j = 0; j < n; j++)
{
for (int k = 0; k < m; k++)
{
// If cell is 0, nothing to do
if (a[j][k] == 0)
continue;
// Check all 8 neighbours and do a Union
// with neighbour's set if neighbour is
// also 1
if (j + 1 < n && a[j + 1][k] == 1)
dus->Union(j * (m) + k,
(j + 1) * (m) + k);
if (j - 1 >= 0 && a[j - 1][k] == 1)
dus->Union(j * (m) + k,
(j - 1) * (m) + k);
if (k + 1 < m && a[j][k + 1] == 1)
dus->Union(j * (m) + k,
(j) * (m) + k + 1);
if (k - 1 >= 0 && a[j][k - 1] == 1)
dus->Union(j * (m) + k,
(j) * (m) + k - 1);
if (j + 1 < n && k + 1 < m &&
a[j + 1][k + 1] == 1)
dus->Union(j * (m) + k,
(j + 1) * (m) + k + 1);
if (j + 1 < n && k - 1 >= 0 &&
a[j + 1][k - 1] == 1)
dus->Union(j * m + k,
(j + 1) * (m) + k - 1);
if (j - 1 >= 0 && k + 1 < m &&
a[j - 1][k + 1] == 1)
dus->Union(j * m + k,
(j - 1) * m + k + 1);
if (j - 1 >= 0 && k - 1 >= 0 &&
a[j - 1][k - 1] == 1)
dus->Union(j * m + k,
(j - 1) * m + k - 1);
}
}
// Array to note down frequency of each set
int *c = new int[n * m];
int numberOfIslands = 0;
for (int j = 0; j < n; j++)
{
for (int k = 0; k < m; k++)
{
if (a[j][k] == 1)
{
int x = dus->find(j * m + k);
// If frequency of set is 0,
// increment numberOfIslands
if (c[x] == 0)
{
numberOfIslands++;
c[x]++;
}
else
c[x]++;
}
}
}
return numberOfIslands;
}
// Driver Code
int main(void)
{
vector>a = {{1, 1, 0, 0, 0},
{0, 1, 0, 0, 1},
{1, 0, 0, 1, 1},
{0, 0, 0, 0, 0},
{1, 0, 1, 0, 1}};
cout << "Number of Islands is: "
<< countIslands(a) << endl;
}
// This code is contributed by ankush_953
Java
// Java program to fnd number of islands using Disjoint
// Set data structure.
import java.io.*;
import java.util.*;
public class Main
{
public static void main(String[] args)throws IOException
{
int[][] a = new int[][] {{1, 1, 0, 0, 0},
{0, 1, 0, 0, 1},
{1, 0, 0, 1, 1},
{0, 0, 0, 0, 0},
{1, 0, 1, 0, 1}
};
System.out.println("Number of Islands is: " +
countIslands(a));
}
// Returns number of islands in a[][]
static int countIslands(int a[][])
{
int n = a.length;
int m = a[0].length;
DisjointUnionSets dus = new DisjointUnionSets(n*m);
/* The following loop checks for its neighbours
and unites the indexes if both are 1. */
for (int j=0; j= 0 && a[j-1][k]==1)
dus.union(j*(m)+k, (j-1)*(m)+k);
if (k+1 < m && a[j][k+1]==1)
dus.union(j*(m)+k, (j)*(m)+k+1);
if (k-1 >= 0 && a[j][k-1]==1)
dus.union(j*(m)+k, (j)*(m)+k-1);
if (j+1=0 && a[j+1][k-1]==1)
dus.union(j*m+k, (j+1)*(m)+k-1);
if (j-1>=0 && k+1=0 && k-1>=0 && a[j-1][k-1]==1)
dus.union(j*m+k, (j-1)*m+k-1);
}
}
// Array to note down frequency of each set
int[] c = new int[n*m];
int numberOfIslands = 0;
for (int j=0; j
Python3
# Python3 program to find
# the number of islands using
# Disjoint Set data structure.
# Class to represent
# Disjoint Set Data structure
class DisjointUnionSets:
def __init__(self, n):
self.rank = [0] * n
self.parent = [0] * n
self.n = n
self.makeSet()
def makeSet(self):
# Initially, all elements are in their
# own set.
for i in range(self.n):
self.parent[i] = i
# Finds the representative of the set that x
# is an element of
def find(self, x):
if (self.parent[x] != x):
# if x is not the parent of itself,
# then x is not the representative of
# its set.
# so we recursively call Find on its parent
# and move i's node directly under the
# representative of this set
return self.find(self.parent[x])
return x
# Unites the set that includes x and
# the set that includes y
def Union(self, x, y):
# Find the representatives(or the root nodes)
# for x an y
xRoot = self.find(x)
yRoot = self.find(y)
# Elements are in the same set,
# no need to unite anything.
if xRoot == yRoot:
return
# If x's rank is less than y's rank
# Then move x under y so that depth of tree
# remains less
if self.rank[xRoot] < self.rank[yRoot]:
parent[xRoot] = yRoot
# Else if y's rank is less than x's rank
# Then move y under x so that depth of tree
# remains less
elif self.rank[yRoot] < self.rank[xRoot]:
self.parent[yRoot] = xRoot
else:
# Else if their ranks are the same
# Then move y under x (doesn't matter
# which one goes where)
self.parent[yRoot] = xRoot
# And increment the result tree's
# rank by 1
self.rank[xRoot] = self.rank[xRoot] + 1
# Returns number of islands in a[][]
def countIslands(a):
n = len(a)
m = len(a[0])
dus = DisjointUnionSets(n * m)
# The following loop checks for its neighbours
# and unites the indexes if both are 1.
for j in range(0, n):
for k in range(0, m):
# If cell is 0, nothing to do
if a[j][k] == 0:
continue
# Check all 8 neighbours and do a Union
# with neighbour's set if neighbour is
# also 1
if j + 1 < n and a[j + 1][k] == 1:
dus.Union(j * (m) + k,
(j + 1) * (m) + k)
if j - 1 >= 0 and a[j - 1][k] == 1:
dus.Union(j * (m) + k,
(j - 1) * (m) + k)
if k + 1 < m and a[j][k + 1] == 1:
dus.Union(j * (m) + k,
(j) * (m) + k + 1)
if k - 1 >= 0 and a[j][k - 1] == 1:
dus.Union(j * (m) + k,
(j) * (m) + k - 1)
if (j + 1 < n and k + 1 < m and
a[j + 1][k + 1] == 1):
dus.Union(j * (m) + k, (j + 1) *
(m) + k + 1)
if (j + 1 < n and k - 1 >= 0 and
a[j + 1][k - 1] == 1):
dus.Union(j * m + k, (j + 1) *
(m) + k - 1)
if (j - 1 >= 0 and k + 1 < m and
a[j - 1][k + 1] == 1):
dus.Union(j * m + k, (j - 1) *
m + k + 1)
if (j - 1 >= 0 and k - 1 >= 0 and
a[j - 1][k - 1] == 1):
dus.Union(j * m + k, (j - 1) *
m + k - 1)
# Array to note down frequency of each set
c = [0] * (n * m)
numberOfIslands = 0
for j in range(n):
for k in range(n):
if a[j][k] == 1:
x = dus.find(j * m + k)
# If frequency of set is 0,
# increment numberOfIslands
if c[x] == 0:
numberOfIslands += 1
c[x] += 1
else:
c[x] += 1
return numberOfIslands
# Driver Code
a = [[1, 1, 0, 0, 0],
[0, 1, 0, 0, 1],
[1, 0, 0, 1, 1],
[0, 0, 0, 0, 0],
[1, 0, 1, 0, 1]]
print("Number of Islands is:", countIslands(a))
# This code is contributed by ankush_953
C#
// C# program to fnd number of islands using Disjoint
// Set data structure.
using System;
class GFG
{
public static void Main(String[] args)
{
int[,] a = new int[,] {{1, 1, 0, 0, 0},
{0, 1, 0, 0, 1},
{1, 0, 0, 1, 1},
{0, 0, 0, 0, 0},
{1, 0, 1, 0, 1}
};
Console.WriteLine("Number of Islands is: " +
countIslands(a));
}
// Returns number of islands in[,]a
static int countIslands(int[,]a)
{
int n = a.GetLength(0);
int m = a.GetLength(1);
DisjointUnionSets dus = new DisjointUnionSets(n * m);
/* The following loop checks for its neighbours
and unites the indexes if both are 1. */
for (int j = 0; j < n; j++)
{
for (int k = 0; k < m; k++)
{
// If cell is 0, nothing to do
if (a[j, k] == 0)
continue;
// Check all 8 neighbours and do a union
// with neighbour's set if neighbour is
// also 1
if (j + 1 < n && a[j + 1, k] == 1)
dus.union(j * (m) + k, (j + 1) * (m) + k);
if (j - 1 >= 0 && a[j - 1, k] == 1)
dus.union(j * (m) + k, (j - 1) * (m) + k);
if (k + 1 < m && a[j, k + 1] == 1)
dus.union(j * (m) + k, (j) * (m) + k + 1);
if (k-1 >= 0 && a[j,k-1]==1)
dus.union(j * (m) + k, (j) * (m) + k - 1);
if (j + 1 < n && k + 1 < m && a[j + 1, k + 1] == 1)
dus.union(j * (m) + k, (j + 1) * (m) + k + 1);
if (j + 1 < n && k - 1 >= 0 && a[j + 1,k - 1] == 1)
dus.union(j * m + k, (j + 1) * (m) + k - 1);
if (j - 1 >= 0 && k + 1 < m && a[j - 1, k + 1] == 1)
dus.union(j * m + k, (j - 1) * m + k + 1);
if (j - 1 >= 0 && k - 1 >= 0 && a[j - 1, k - 1] == 1)
dus.union(j * m + k, (j - 1) * m + k - 1);
}
}
// Array to note down frequency of each set
int[] c = new int[n*m];
int numberOfIslands = 0;
for (int j = 0; j < n; j++)
{
for (int k = 0; k < m; k++)
{
if (a[j, k] == 1)
{
int x = dus.find(j * m + k);
// If frequency of set is 0,
// increment numberOfIslands
if (c[x] == 0)
{
numberOfIslands++;
c[x]++;
}
else
c[x]++;
}
}
}
return numberOfIslands;
}
}
// Class to represent Disjoint Set Data structure
class DisjointUnionSets
{
int[] rank, parent;
int n;
public DisjointUnionSets(int n)
{
rank = new int[n];
parent = new int[n];
this.n = n;
makeSet();
}
public void makeSet()
{
// Initially, all elements are in their
// own set.
for (int i = 0; i < n; i++)
parent[i] = i;
}
// Finds the representative of the set that x
// is an element of
public int find(int x)
{
if (parent[x] != x)
{
// if x is not the parent of itself,
// then x is not the representative of
// its set.
// so we recursively call Find on its parent
// and move i's node directly under the
// representative of this set
return find(parent[x]);
}
return x;
}
// Unites the set that includes x and the set
// that includes y
public void union(int x, int y)
{
// Find the representatives (or the root nodes)
// for x an y
int xRoot = find(x);
int yRoot = find(y);
// Elements are in the same set, no need
// to unite anything.
if (xRoot == yRoot)
return;
// If x's rank is less than y's rank
// Then move x under y so that depth of tree
// remains less
if (rank[xRoot] < rank[yRoot])
parent[xRoot] = yRoot;
// Else if y's rank is less than x's rank
// Then move y under x so that depth of tree
// remains less
else if(rank[yRoot] < rank[xRoot])
parent[yRoot] = xRoot;
else // Else if their ranks are the same
{
// Then move y under x (doesn't matter
// which one goes where)
parent[yRoot] = xRoot;
// And increment the result tree's
// rank by 1
rank[xRoot] = rank[xRoot] + 1;
}
}
}
// This code is contributed by PrinciRaj1992
输出:
Number of Islands is: 5