Link: https://leetcode-cn.com/problems/number-of-provinces/
There is n
a city, some of which are connected to each other, and others are not connected. If the city a
is b
directly connected to the city , and the city b
is c
directly connected to the city, then the city a
is c
indirectly connected to the city .
A province is a group of directly or indirectly connected cities. The group does not contain other unconnected cities.
Give you a n x n
matrix isConnected
, which isConnected[i][j] = 1
means that the i
first city and the j
first city are directly connected, but isConnected[i][j] = 0
that the two are not directly connected.
Returns the number of provinces in the matrix .
Example 1:
Input: isConnected = [[1,1,0],[1,1,0],[0,0,1]] Output: 2
Example 2:
Input: isConnected = [[1,0,0],[0,1,0],[0,0,1]] Output: 3
prompt:
1 <= n <= 200
n == isConnected.length
n == isConnected[i].length
isConnected[i][j]
For1
or0
isConnected[i][i] == 1
isConnected[i][j] == isConnected[j][i]
Idea: It is an obvious problem of union search. It starts with n independent sets, and each time they are merged, the number of sets decreases by 1. We use path compression for optimization (adding rank-based merging is also possible, but if the time is not particularly deadly, the optimization of rank-based merging is limited, which will increase the code complexity).
class Solution {
public:
int Father[210];
int Find(int x){
if( x != Father[x] ){
return Father[x] = Find(Father[x]);
}
return Father[x];
}
void Union(int A,int B,int &Single){
int FA = Find(A), FB = Find(B);
if( FA != FB ){
Father[FA] = FB;
-- Single;//每成功合并一次 集合数就少一
}
}
int findCircleNum(vector<vector<int>>& isConnected) {
int n = isConnected.size(), i, j, Single = n;
for(i = 0; i < n; ++ i){
Father[i] = i;
}
for(i = 0; i < n; ++ i){
for(j = 0; j < n; ++ j){
if( isConnected[i][j] ){
Union(i, j, Single);
}
}
}
return Single;
}
};
Increase the combined version by rank:
class Solution {
public:
int Father[210];
int Rank[210];
int Find(int x){
if( x != Father[x] ){
return Father[x] = Find(Father[x]);
}
return Father[x];
}
void Union(int A,int B,int &Single){
int FA = Find(A), FB = Find(B);
if( FA != FB ){
if(Rank[FA] < Rank[FB]){
Father[FA] = FB;
}else if(Rank[FA] == Rank[FB]){
Father[FA] = FB;
++ Rank[FB];
}else{
Father[FB] = FA;
}
-- Single;//每成功合并一次 集合数就少一
}
}
int findCircleNum(vector<vector<int>>& isConnected) {
int n = isConnected.size(), i, j, Single = n;
memset(Rank,0,sizeof(Rank));
for(i = 0; i < n; ++ i){
Father[i] = i;
}
for(i = 0; i < n; ++ i){
for(j = 0; j < n; ++ j){
if( isConnected[i][j] ){
Union(i, j, Single);
}
}
}
return Single;
}
};
This way of writing is to ensure that Rank correctly reflects the height of the tree, but at the same time, overly complex if-else statements will reduce the execution performance of the program. If we do not need to ensure the correctness of Rank, we can:
class Solution {
public:
int Father[210];
int Rank[210];
int Find(int x){
if( x != Father[x] ){
return Father[x] = Find(Father[x]);
}
return Father[x];
}
void Union(int A,int B,int &Single){
int FA = Find(A), FB = Find(B);
if( FA != FB ){
if(Rank[FA] < Rank[FB]){
Father[FA] = FB;
++ Rank[FB];
}else{
Father[FB] = FA;
++ Rank[FA];
}
-- Single;//每成功合并一次 集合数就少一
}
}
int findCircleNum(vector<vector<int>>& isConnected) {
int n = isConnected.size(), i, j, Single = n;
memset(Rank,0,sizeof(Rank));
for(i = 0; i < n; ++ i){
Father[i] = i;
}
for(i = 0; i < n; ++ i){
for(j = 0; j < n; ++ j){
if( isConnected[i][j] ){
Union(i, j, Single);
}
}
}
return Single;
}
};