Open azl397985856 opened 2 years ago
https://leetcode.com/problems/number-of-provinces/
BFS
class Solution {
public int findCircleNum(int[][] isConnected) {
if(isConnected == null || isConnected.length == 0){
return 0;
}
int n = isConnected.length;
int[] visited = new int[n];
int res = 0;
for(int i = 0; i < n; i++){
if(visited[i] == 0){
visited[i] = 1;
res++;
bfs(isConnected, i, visited);
}
}
return res;
}
private void bfs(int[][] isConnected, int i, int[] visited){
Queue<Integer> q = new LinkedList<>();
q.offer(i);
while(!q.isEmpty()){
int row = q.poll();
for(int col = 0; col < isConnected.length; col++){
if(visited[col] == 0 && isConnected[row][col] == 1){
visited[col] = 1;
q.offer(col);
}
}
}
}
}
DFS
class Solution {
public int findCircleNum(int[][] isConnected) {
if(isConnected == null || isConnected.length == 0){
return 0;
}
int n = isConnected.length;
int[] visited = new int[n];
int res = 0;
for(int i = 0; i < n; i++){
if(visited[i] == 0){
visited[i] = 1;
res++;
dfs(isConnected, i, visited);
}
}
return res;
}
private void dfs(int[][] isConnected, int row, int[] visited){
for(int col = 0; col < isConnected.length; col++){
if(visited[col] == 0 && isConnected[row][col] == 1){
visited[col] = 1;
dfs(isConnected, col, visited);
}
}
}
}
union find
class Solution {
public int findCircleNum(int[][] isConnected) {
int n = isConnected.length;
int[] parent = new int[n];
for(int i = 0; i < n; i++){
parent[i] = i;
}
for(int i = 0; i < n; i++){
for(int j = i + 1; j < n; j++) // note j is from i + 1 to avoid duplicate and meaningless processing
if(isConnected[i][j] == 1){
union(parent, i, j);
}
}
System.out.println("parent: " + Arrays.toString(parent));
int res = 0;
for(int i = 0; i < n; i++){
if(parent[i] == i){
res++;
}
}
return res;
}
private void union(int[] parent, int i, int j){
parent[find(parent, i)] = find(parent, j); // note that need to call find to find the ancestor for i and j then union
}
private int find(int[] parent, int i){
if(parent[i] != i){
parent[i] = find(parent, parent[i]);
}
return parent[i];
}
}
思路: 方法一、Hashmap/set/数组 + DFS 方法二、Hashmap/set/数组 + BFS 方法三、并查集
方法一、Hashmap + DFS
方法二、Hashmap + BFS
方法三、Union Find
代码(C++):
方法三、
class UnionFind {
vector<int> parent;
public:
int circle;
UnionFind(int n) {
parent = vector<int>(n, 0);
circle = n;
for (int i = 0; i < n; ++i)
parent[i] = i;
}
int Find(int x) {
int r = x;
while (r != parent[r])
r = parent[r];
return r;
}
void Union(int x, int y) {
int p = Find(x);
int q = Find(y);
if (p != q) {
parent[p] = q;
circle--;
}
}
};
class Solution {
public:
int findCircleNum(vector<vector<int>>& isConnected) {
int n = isConnected.size();
UnionFind u(n);
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
if (isConnected[i][j]) {
u.Union(i, j);
}
}
}
return u.circle;
}
};
class UF:
def __init__(self, n) -> None:
self.parent = {i: i for i in range(n)}
self.size = n
def find(self, i):
if self.parent[i] != i:
self.parent[i] = self.find(self.parent[i])
return self.parent[i]
def connect(self, i, j):
root_i, root_j = self.find(i), self.find(j)
if root_i != root_j:
self.size -= 1
self.parent[root_i] = root_j
class Solution:
def findCircleNum(self, isConnected: List[List[int]]) -> int:
n = len(isConnected)
uf = UF(n)
for i in range(n):
for j in range(n):
if isConnected[i][j]:
uf.connect(i, j)
return uf.size
union find
class Solution {
public:
int find(vector<int>& parent, int idx) {
if (parent[idx] != idx) {
parent[idx] = find(parent, parent[idx]);
}
return parent[idx];
}
void getUnion(vector<int>& parent, int idx1, int idx2) {
parent[find(parent, idx1)] = find(parent, idx2);
}
int findCircleNum(vector<vector<int>>& isConnected) {
vector<int> parent(isConnected.size());
for (int i = 0; i < isConnected.size(); ++i) {
parent[i] = i;
}
for (int i = 0; i < isConnected.size(); ++i) {
for (int j = i + 1; j < isConnected.size(); ++j) {
if (isConnected[i][j] == 1) {
getUnion(parent, i, j);
}
}
}
int res = 0;
for (int i = 0; i < parent.size(); ++i) {
if (parent[i] == i) res++;
}
return res;
}
};
数组+bfs
class Solution {
public int findCircleNum(int[][] isConnected) {
int n = isConnected.length;
boolean[] visited = new boolean[n];
int ans = 0;
LinkedList<Integer> dq = new LinkedList<>();
for(int j = 0;j < n ;j++){
if(!visited[j]){
ans++;
dq.offer(j);
visited[j] = true;
while(!dq.isEmpty()){
int x = dq.poll();
for(int i = 0; i< n ; i++){
if(!visited[i] && isConnected[x][i] == 1){
dq.offer(i);
visited[i] = true;
}
}
}
}
}
return ans;
}
}
时间复杂度:O(n*n) 空间复杂度:O(n)
//DFS
class Solution {
public int findCircleNum(int[][] isConnected) {
int count = 0;
boolean[] visited = new boolean[isConnected.length];
for (int i = 0; i < isConnected.length; i++){
if(!visited[i]){ //新的连通分量
dfs(isConnected,visited,i);
count++;
}
}
return count++;
}
public void dfs (int[][] isConnected, boolean[] visited, int i){
for(int j = 0; j < isConnected.length; j++) {
if (isConnected[i][j] == 1 && visited[j] != true){
visited[j] = true; //标记在同一个连通分量的城市
dfs(isConnected,visited,j);
}
}
}
}
/**
* @param {number[][]} isConnected
* @return {number}
*/
const findCircleNum3 = function(isConnected) { // Union Find, Time: O(n^2), Space: O(n)
const n = isConnected.length;
const dsu = new DSU(n);
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
if (isConnected[i][j] && i !== j) {
dsu.union(i, j);
}
}
}
return dsu.count;
};
class DSU {
constructor(n) {
this.parent = Array.from(Array(n).keys());
this.count = n;
}
find(x) {
if (this.parent[x] !== x) {
this.parent[x] = this.find(this.parent[x]); // path compression
}
return this.parent[x];
}
union(x, y) {
const rootX = this.find(x);
const rootY = this.find(y);
if (rootX !== rootY) {
this.parent[Math.min(rootX, rootY)] = Math.max(rootX, rootY);
this.count -= 1;
}
}
}
Using Union Find
class Solution:
def findCircleNum(self, isConnected: List[List[int]]) -> int:
union_map=list(range(len(isConnected)))
count=len(isConnected)
def find(a):
while union_map[a] !=a:
a=union_map[a]
return a
def union(a,b):
nonlocal count
a_root=find(a)
b_root=find(b)
if a_root != b_root:
count-=1
union_map[b_root]=a_root
for i in range(len(isConnected)):
for j in range(i+1,len(isConnected)):
if isConnected[i][j]==1:
union(i,j)
return count
Time: O(n*2logn) n is the length of isConnected
Space: O(n)
class UnionFind {
// 记录父节点
private Map<Integer,Integer> father;
// 记录集合的数量
private int numOfSets = 0;
public UnionFind() {
father = new HashMap<Integer,Integer>();
numOfSets = 0;
}
public void add(int x) {
if (!father.containsKey(x)) {
father.put(x, null);
numOfSets++;
}
}
public void merge(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY){
father.put(rootX,rootY);
numOfSets--;
}
}
public int find(int x) {
int root = x;
while(father.get(root) != null){
root = father.get(root);
}
while(x != root){
int original_father = father.get(x);
father.put(x,root);
x = original_father;
}
return root;
}
public boolean isConnected(int x, int y) {
return find(x) == find(y);
}
public int getNumOfSets() {
return numOfSets;
}
}
class Solution {
public int findCircleNum(int[][] isConnected) {
UnionFind uf = new UnionFind();
for(int i = 0;i < isConnected.length;i++){
uf.add(i);
for(int j = 0;j < i;j++){
if(isConnected[i][j] == 1){
uf.merge(i,j);
}
}
}
return uf.getNumOfSets();
}
}
Explanation
Code
class Solution:
def findCircleNum(self, isConnected: List[List[int]]) -> int:
adj = defaultdict(list)
for a in range(len(isConnected)):
for b in range(len(isConnected[0])):
if a != b and isConnected[a][b] == 1:
adj[a].append(b)
def dfs(n):
nonlocal count, adj, visited
visited.add(n)
for i in adj[n]:
if i not in visited:
dfs(i)
visited = set()
count = 0
for k in adj.keys():
if k not in visited:
count += 1
dfs(k)
return count + len(isConnected) - len(visited)
Time complexity: O(v+e) where v is the length of cities and e is the edge/connection between cities
Space complexity: O(v+e)
并查集
class UnionFind {
int[] parent;
int size;
public UnionFind(int n) {
size = n;
parent = new int[n];
for (int i = 0; i < n; i++) parent[i] = i;
}
public int find(int i) {
while (parent[i] != i) i = parent[i];
return i;
}
public void union(int i, int j) {
int pi = find(i);
int pj = find(j);
if (pi != pj) {
parent[pi] = pj;
size--;
}
}
public int size() {
return size;
}
}
class Solution {
public int findCircleNum(int[][] isConnected) {
int n = isConnected.length;
UnionFind uf = new UnionFind(n);
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
if (isConnected[i][j] == 1) uf.union(i, j);
}
}
return uf.size();
}
}
class Solution(object):
def findCircleNum(self, isConnected):
"""
:type isConnected: List[List[int]]
:rtype: int
"""
def find(index):
if parent[index] != index:
parent[index] = find(parent[index])
return parent[index]
def union(index1, index2):a
parent[find(index1)] = find(index2)
provinces = len(isConnected)
parent = list(range(provinces))
for i in range(provinces):
for j in range(i + 1, provinces):
if isConnected[i][j] == 1:
union(i, j)
circles = sum(parent[i] == i for i in range(provinces))
return circles
时间复杂度:O(n^2 *logn) 空间复杂度:O(n^2)
class Solution {
public int findCircleNum(int[][] isConnected) {
Map<Integer, String> visited = new HashMap<Integer, String>();
for (int i = 0; i < isConnected.length; i++) {
visited.put(i, "unvisited");
}
int connected_num = 0;
for (int i = 0; i < isConnected.length; i++) {
if (visited.get(i) == "unvisited") {
connected_num += 1;
dfs(visited, i, isConnected);
}
}
return connected_num;
}
public void dfs(Map visited, int city, int[][] isConnected) {
visited.put(city, "pending");
for (int i = 0; i< isConnected.length; i++) {
if ((isConnected[city][i] == 1) & (visited.get(i) == "unvisited")) {
dfs(visited, i, isConnected);
}
}
visited.put(city, "visited");
}
}
time: O(n)
space: O(n)
var findCircleNum = function (isConnected) {
let city = isConnected.length;
let visited = new Array(city);
let count = 0;
function dfs(now, isConnected, visited) {//深度优先遍历
if (!visited[now]) {
visited[now]=true;
for (let i = 0; i < isConnected[now].length; i++) {
//该节点联通的所有节点
if (isConnected[now][i]) {
//向下遍历
dfs(i, isConnected,visited)
}
}
}else{
return;
}
}
for(let start=0;start<city;start++){
if(!visited[start]){
count++;//每一个不被访问过的都是一个联通域
dfs(start,isConnected,visited)
}
}
return count;
};
时间复杂度:O(nn)//遍历nn的邻接矩阵 空间复杂度:O(n)
public class Solution {
public void dfs(int[][] M, int[] visited, int i) {
for (int j = 0; j < M.length; j++) {
if (M[i][j] == 1 && visited[j] == 0) {
visited[j] = 1;
dfs(M, visited, j);
}
}
}
public int findCircleNum(int[][] M) {
int[] visited = new int[M.length];
int count = 0;
for (int i = 0; i < M.length; i++) {
if (visited[i] == 0) {
dfs(M, visited, i);
count++;
}
}
return count;
}
}
class Solution:
def __init__(self):
self.isConnected = None
self.n = 0
self.res = 0
self.visited = None
def findCircleNum(self, isConnected: List[List[int]]) -> int:
self.isConnected = isConnected
self.n = len(isConnected)
self.visited = [0] * self.n
for i in range(self.n):
if not self.visited[i]:
self.dfs(i)
self.res += 1
return self.res
def dfs(self, i):
for j in range(self.n):
if i != j and self.isConnected[i][j] and not self.visited[j]:
self.visited[j] = 1
self.dfs(j)
class Solution:
def findCircleNum(self, isConnected: List[List[int]]) -> int:
n = len(isConnected)
visited = [0] * n
deque = collections.deque()
res = 0
for i in range(n):
if not visited[i]:
res += 1
visited[i] = 1
deque.append(i)
while len(deque):
curr = deque.popleft()
for j in range(n):
if j != curr and isConnected[curr][j] and not visited[j]:
deque.append(j)
visited[j] = 1
return res
class Solution:
def findCircleNum(self, isConnected: List[List[int]]) -> int:
def find(index: int):
if parent[index] != index:
parent[index] = find(parent[index])
return parent[index]
def union(index_1: int , index_2: int):
parent[find(index_1)] = find(index_2)
n = len(isConnected)
parent = list(range(n))
for i in range(n):
for j in range(i+1, n):
if isConnected[i][j]:
union(i, j)
return sum(parent[i] == i for i in range(n))
class Solution:
def findCircleNum(self, isConnected: List[List[int]]) -> int:
N = len(isConnected)
res = 0
parent = [i for i in range(N)]
def union(parent, i, j):
parent[find(parent, i)] = find(parent, j)
def find(parent,i):
while parent[i] != i:
parent[i] = parent[parent[i]]
i = parent[i]
return i
for i in range(N):
for j in range(N):
if isConnected[i][j] == 1:
union(parent, i, j)
for i in range(N):
if parent[i] == i:
res += 1
return res
class Solution {
private:
int Find(vector<int>& parent, int index) {
if (parent[index] != index) {
parent[index] = Find(parent, parent[index]);
}
return parent[index];
}
void Union(vector<int>& parent, int index1, int index2) {
parent[Find(parent, index1)] = Find(parent, index2);
}
public:
int findCircleNum(vector<vector<int>>& isConnected) {
int count = isConnected.size();
vector<int> parent(count);
for (int i = 0; i < count; ++i) {
parent[i] = i;
}
for (int i = 0; i < count; i++) {
for (int j = i + 1; j < count; ++j) {
if (isConnected[i][j] == 1) {
Union(parent, i, j);
}
}
}
int res = 0;
for (int i = 0; i < count; ++i) {
if (parent[i] == i) {
++res;
}
}
return res;
}
};
并查集,第一次听说^^
class Solution {
public int findCircleNum(int[][] isConnected) {
int length = isConnected.length;
UF uf = new UF(length);
for(int i = 0 ; i< length ; i++) {
for(int j = i + 1; j< length ; j ++) {
if(isConnected[i][j] == 1) {
uf.union(i, j);
}
}
}
return uf.size;
}
private class UF{
int size;
final int[] node;
public UF(int length) {
this.node = new int[length];
int idx = 0;
while(idx <= this.node.length - 1) {
node[idx] = idx;
idx ++;
}
this.size = length;
}
public void union(int p, int q) {
p = findRoot(p);
q = findRoot(q);
if(p != q){
node[p] = q;
// 合并两个节点的根 孤岛减少一个
this.size --;
}
}
private int findRoot_slow(int p) {
while(node[p] != p) {
p = node[p];
}
return p;
}
// 这种更快
private int findRoot(int p) {
if(node[p] == p) {
return p;
}
// 级联修改 遍历路径上每个都改
// 同时压缩节点到根节点的值路径
return node[p] = findRoot(root[p]);
}
}
}
class Solution { public int findCircleNum(int[][] isConnected) { int provinces = isConnected.length; int[] parent = new int[provinces]; for (int i = 0; i < provinces; i++) { parent[i] = i; } for (int i = 0; i < provinces; i++) { for (int j = i + 1; j < provinces; j++) { if (isConnected[i][j] == 1) { union(parent, i, j); } } } int circles = 0; for (int i = 0; i < provinces; i++) { if (parent[i] == i) { circles++; } } return circles; }
public void union(int[] parent, int index1, int index2) {
parent[find(parent, index1)] = find(parent, index2);
}
public int find(int[] parent, int index) {
if (parent[index] != index) {
parent[index] = find(parent, parent[index]);
}
return parent[index];
}
}
dfs
使用语言:Python3
class Solution:
def findCircleNum(self, isConnected: List[List[int]]) -> int:
visited = [0] * len(isConnected)
count = 0
for i in range(len(isConnected)):
if visited[i] == 0:
self.dfs(isConnected, visited, i)
count += 1
return count
def dfs(self, isConnected, visited, i):
for j in range(len(isConnected)):
if isConnected[i][j] == 1 and visited[j] == 0:
visited[j] = 1
self.dfs(isConnected, visited, j)
复杂度分析 时间复杂度:O(n^2), n is the number of city 空间复杂度:O(n)
int ufsFind(vector<int>& ufs, int x) {
if (ufs[x] < 0)
return x;
return ufsFind(ufs, ufs[x]);
}
int ufsUnion(vector<int>& ufs, int x, int y) {
int rx = ufsFind(ufs, x);
int ry = ufsFind(ufs, y);
if (rx == ry)
return -1;
ufs[rx] += ufs[ry];
ufs[ry] = rx;
return ufs[rx];
}
int findCircleNum(vector<vector<int>>& isConnected, int n) {
int res = 0;
vector<int> ufs(n, -1);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (isConnected[i][j] == 1)
ufsUnion(ufs, i, j);
}
}
for (auto& v : ufs) {
if (v < 0)
res++;
}
return res;
}
并查集
class Solution:
def findCircleNum(self, isConnected: List[List[int]]) -> int:
n=len(isConnected)
visited=[0]*n
def dfs(i):
visited[i]=1
for j in range(n):
if isConnected[i][j]==1 and visited[j]==0:
dfs(j)
c=0
for i in range(n):
if visited[i]==0:
dfs(i)
c+=1
return c
class Solution {
public int findCircleNum(int[][] isConnected) {
int provinces = isConnected.length;
boolean[] visited = new boolean[provinces];
int circles = 0;
Queue<Integer> queue = new LinkedList<Integer>();
for (int i = 0; i < provinces; i++) {
if (!visited[i]) {
queue.offer(i);
while (!queue.isEmpty()) {
int j = queue.poll();
visited[j] = true;
for (int k = 0; k < provinces; k++) {
if (isConnected[j][k] == 1 && !visited[k]) {
queue.offer(k);
}
}
}
circles++;
}
}
return circles;
}
}
class Solution {
public:
int Find(vector<int>& parent, int index) {
if (parent[index] != index) {
parent[index] = Find(parent, parent[index]);
}
return parent[index];
}
void Union(vector<int>& parent, int index1, int index2) {
parent[Find(parent, index1)] = Find(parent, index2);
}
int findCircleNum(vector<vector<int>>& isConnected) {
int provinces = isConnected.size();
vector<int> parent(provinces);
for (int i = 0; i < provinces; i++) {
parent[i] = i;
}
for (int i = 0; i < provinces; i++) {
for (int j = i + 1; j < provinces; j++) {
if (isConnected[i][j] == 1) {
Union(parent, i, j);
}
}
}
int circles = 0;
for (int i = 0; i < provinces; i++) {
if (parent[i] == i) {
circles++;
}
}
return circles;
}
};
思路 并查集 dfs python3 class Solution: def findCircleNum(self, isConnected: List[List[int]]) -> int: n=len(isConnected) visited=[0]*n def dfs(i): visited[i]=1 for j in range(n): if isConnected[i][j]==1 and visited[j]==0: dfs(j) c=0 for i in range(n): if visited[i]==0: dfs(i) c+=1 return c
AC
class Solution {
public int findCircleNum(int[][] isConnected) {
int n = isConnected.length;
UF uf = new UF(n);
for(int row = 0;row < n;row++){
for(int col = row;col < n;col++){
if(row == col) continue;
if(isConnected[row][col] == 1)
uf.union(row, col);
}
}
int count = 0;
for(int weight: uf.weights){
if(weight > 0)
count++;
}
return count;
}
private class UF{
int[] p, weights;
public UF(int N){
p = new int[N];
for(int i = 0;i < N;i++){
p[i] = i;
}
weights = new int[N];
Arrays.fill(weights, 1);
}
public int find(int a){
if(p[a] != a){
p[a] = find(p[a]);
}
return p[a];
}
public boolean connected(int a, int b){
return find(a) == find(b);
}
public void union(int a, int b){
int pa = find(a);
int pb = find(b);
if(pa != pb){
p[pa] = pb;
weights[pb] += weights[pa];
weights[pa] = 0;
}
}
}
}
time: N为矩阵大小,O(NlogN) space: O(N);
class Solution {
public int findCircleNum(int[][] isConnected) {
int provinces = isConnected.length;
int[] parent = new int[provinces];
for (int i = 0; i < provinces; i++) {
parent[i] = i;
}
for (int i = 0; i < provinces; i++) {
for (int j = i + 1; j < provinces; j++) {
if (isConnected[i][j] == 1) {
union(parent, i, j);
}
}
}
int circles = 0;
for (int i = 0; i < provinces; i++) {
if (parent[i] == i) {
circles++;
}
}
return circles;
}
public void union(int[] parent, int index1, int index2) {
parent[find(parent, index1)] = find(parent, index2);
}
public int find(int[] parent, int index) {
if (parent[index] != index) {
parent[index] = find(parent, parent[index]);
}
return parent[index];
}
}
时间复杂度:O(N^2*LogN) 空间复杂度:O(N)
class Solution { public int findCircleNum(int[][] isConnected) { int provinces = isConnected.length; boolean[] visited = new boolean[provinces]; int circles = 0; for (int i = 0; i < provinces; i++) { if (!visited[i]) { dfs(isConnected, visited, provinces, i); circles++; } } return circles; }
public void dfs(int[][] isConnected, boolean[] visited, int provinces, int i) {
for (int j = 0; j < provinces; j++) {
if (isConnected[i][j] == 1 && !visited[j]) {
visited[j] = true;
dfs(isConnected, visited, provinces, j);
}
}
}
}
该题可以通过暴力法和使用前缀树的方式(暴力法则是使用深度优先搜索或者广度优先搜索)
class Solution { public int findCircleNum(int[][] isConnected) { if(isConnected==null||isConnected.length==0)return 0; int si=isConnected.length; UnidFind uf=new UnidFind(si); for(int i=0;i<si;i++){ for(int j=0;j<si;j++){ if(isConnected[i][j]==1)uf.union(i,j); } } return uf.count; } private class UnidFind{ int count; int[]partent; int[]size; UnidFind(int n){ count=n; partent=new int[n]; size=new int[n]; Arrays.fill(size,1); for(int i=0;i<n;i++)partent[i]=i; } public int findset(int i){ if(partent[i]!=i)partent[i]=findset(partent[i]); return partent[i]; } public void union(int x,int y){ int x1=findset(x); int y1=findset(y); if(x1!=y1){ if(size[x1]>size[y1]){ partent[y1]=x1; }else if(size[x1]<size[y1]){ partent[x1]=y1; }else{ partent[y1]=x1; size[y1]++; } --count; } } public int getcount(){ return count; } } }
时间复杂度:O(nlogn)
空间复杂度:O(n)
class UnionFind:
def __init__(self):
self.father = {}
# 额外记录集合的数量
self.num_of_sets = 0
def find(self,x):
root = x
while self.father[root] != None:
root = self.father[root]
while x != root:
original_father = self.father[x]
self.father[x] = root
x = original_father
return root
def merge(self,x,y):
root_x,root_y = self.find(x),self.find(y)
if root_x != root_y:
self.father[root_x] = root_y
# 集合的数量-1
self.num_of_sets -= 1
def add(self,x):
if x not in self.father:
self.father[x] = None
# 集合的数量+1
self.num_of_sets += 1
class Solution:
def findCircleNum(self, M: List[List[int]]) -> int:
uf = UnionFind()
for i in range(len(M)):
uf.add(i)
for j in range(i):
if M[i][j]:
uf.merge(i,j)
return uf.num_of_sets
func findCircleNum(isConnected [][]int) (ans int) {
n := len(isConnected)
parent := make([]int, n)
for i := range parent {
parent[i] = i
}
var find func(int) int
find = func(x int) int {
if parent[x] != x {
parent[x] = find(parent[x])
}
return parent[x]
}
union := func(form, to int){
parent[find(form)] = find(to)
}
for i, row := range isConnected{
for j := i + 1; j < n ; j++{
if row[j] == 1{
union(i, j)
}
}
}
for i, p := range parent {
if i == p {
ans ++
}
}
return ans
}
class Solution { public int findCircleNum(int[][] isConnected) { int provinces = isConnected.length; boolean[] visited = new boolean[provinces]; int circles = 0; for (int i = 0; i < provinces; i++) { if (!visited[i]) { dfs(isConnected, visited, provinces, i); circles++; } } return circles; }
public void dfs(int[][] isConnected, boolean[] visited, int provinces, int i) {
for (int j = 0; j < provinces; j++) {
if (isConnected[i][j] == 1 && !visited[j]) {
visited[j] = true;
dfs(isConnected, visited, provinces, j);
}
}
}
}
class Solution {
public int findCircleNum(int[][] isConnected) {
int provinces = isConnected.length;
int[] parent = new int[provinces];
for (int i = 0; i < provinces; i++) {
parent[i] = i;
}
for (int i = 0; i < provinces; i++) {
for (int j = i + 1; j < provinces; j++) {
if (isConnected[i][j] == 1) {
union(parent, i, j);
}
}
}
int circles = 0;
for (int i = 0; i < provinces; i++) {
if (parent[i] == i) {
circles++;
}
}
return circles;
}
public void union(int[] parent, int index1, int index2) {
parent[find(parent, index1)] = find(parent, index2);
}
public int find(int[] parent, int index) {
if (parent[index] != index) {
parent[index] = find(parent, parent[index]);
}
return parent[index];
}
}
title: "Day 76 547. 省份数量" date: 2021-11-24T21:42:41+08:00 tags: ["Leetcode", "c++", "UnionFind"] categories: ["91-day-algorithm"] draft: true
有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。
省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。
返回矩阵中 省份 的数量。
示例 1:
输入:isConnected = [[1,1,0],[1,1,0],[0,0,1]]
输出:2
示例 2:
输入:isConnected = [[1,0,0],[0,1,0],[0,0,1]]
输出:3
提示:
1 <= n <= 200
n == isConnected.length
n == isConnected[i].length
isConnected[i][j] 为 1 或 0
isConnected[i][i] == 1
isConnected[i][j] == isConnected[j][i]
- 1、刚好考研今年也新增并查集的学习,所以本次刚好可以复习一下UnionFind class 的相应的写法。
class UnionFind {
private:
unordered_map<int, int> data; //存储父节点
int cnt = 0; //记录数目
public:
int find(int x) {
int root = x;
while(data[root] >= 0) root = data[root];
//路径压缩
while(x != root) {
int tmp = data[x]; //tmp 指向 x 的父节点
data[x] = root; //挂到根节点下
x = tmp;
}
return root; //返回根节点的编号。
}
bool isconnected(int x, int y) {
return find(x) == find(y);
}
void merge(int x, int y) {
int p = find(x);
int q = find(y);
if(p != q) {
data[p] = q;
cnt--;
}
}
void add(int x) {
if(data.count(x) == 0) {
data[x] = -1;
cnt++;
}
}
int getCnt() {
return cnt;
}
};
class Solution {
public:
int findCircleNum(vector<vector<int>>& isConnected) {
UnionFind u;
int n = isConnected.size();
for (int i = 0; i < n; i++) {
u.add(i);
for(int j = 0; j < i; j++) {
if(isConnected[i][j]) u.merge(i, j);
}
}
return u.getCnt();
}
};
class Solution:
def findCircleNum(self, isConnected: List[List[int]]) -> int:
def find(index: int) -> int:
if parent[index] != index:
parent[index] = find(parent[index])
return parent[index]
def union(index1: int, index2: int):
parent[find(index1)] = find(index2)
provinces = len(isConnected)
parent = list(range(provinces))
for i in range(provinces):
for j in range(i + 1, provinces):
if isConnected[i][j] == 1:
union(i, j)
circles = sum(parent[i] == i for i in range(provinces))
return circles
UF模板
class Solution {
class UF {
int[] parent;
int[] size;
int cnt;
UF(int n) {
parent = new int[n];
size = new int[n];
cnt = n;
for (int i = 0; i < n; i++) {
parent[i] = i;
size[i] = 1;
}
}
int find(int node) {
if (parent[node] != node) {
parent[node] = find(parent[node]);
return parent[node];
}
return node;
}
void union(int p, int q) {
if (connected(p, q)) {
return;
}
if (size[find(p)] < size[find(q)]) {
parent[find(p)] = find(q);
size[find(q)] = size[find(q)] + 1;
} else {
parent[find(q)] = find(p);
size[find(p)] = size[find(p)] + 1;
}
cnt--;
}
boolean connected(int p, int q) {
return find(p) == find(q);
}
}
public int findCircleNum(int[][] isConnected) {
int n = isConnected.length;
UF uf = new UF(n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (isConnected[i][j] == 1) {
uf.union(i, j);
}
}
}
return uf.cnt;
}
}
并查集,求连通域个数
class Solution:
def find(self, x): #找x的祖先
if x != self.parent[x]:
self.parent[x] = self.find(self.parent[x]) #路径压缩
return self.parent[x] #这边要返回self.parent[x], 这样每一层递归返回时,都是返回的这一个祖先,这样每次在递归调用处self.parent[x] =赋值时才一直赋值的是这一个祖先
def connected(self, i, j):
return self.find(i) == self.find(j)
def union(self, i, j): #将i的祖先挂到j的祖先下面
if self.connected(i, j): return
ancestor_i = self.find(i)
ancestor_j = self.find(j)
if self.size[ancestor_i] > self.size[ancestor_j]:
self.parent[ancestor_j] = ancestor_i
self.size[ancestor_i] += self.size[ancestor_j]
else:
self.parent[ancestor_i] = ancestor_j
self.size[ancestor_j] += self.size[ancestor_i]
self.cnt -= 1
def findCircleNum(self, isConnected: List[List[int]]) -> int:
#先初始化UF,所有城市独立
n = len(isConnected)
self.parent = {}
self.size = {}
self.cnt = 0
for i in range(n):
self.parent[i] = i
self.size[i] = 1
self.cnt += 1
# i->j =1, 则将i的祖先合并到j的祖先,连通域-1
for i in range(n-1):
for j in range(i+1, n):
if isConnected[i][j] == 1:
self.union(i, j)
return self.cnt
联通了过后需要计数器减一。
class Solution {
vector<int> p;
public:
int findCircleNum(vector<vector<int>>& isConnected) {
int N =isConnected.size();
for(int i=0; i<N; i++)
{
p.push_back(i);
}
int count = N;
for(int i=0; i<N; i++)
{
for(int j=0; j<isConnected[0].size(); j++)
{
if(isConnected[i][j]==1 && findx(i) != findx(j))
{
p[findx(i)] = findx(j);
count--;
}
}
}
return count;
}
int findx(int x)
{
if(p[x]!=x)
p[x] = findx(p[x]);
return p[x];
}
};
Time:O(1) Space:O(n)
https://leetcode.com/problems/number-of-provinces/
const findCircleNum = function(isConnected) {
let visited = new Set, provs = 0;
for(let i = 0; i < isConnected.length; i++) {
if(!(visited.has(i))) {
provs++;
DFS(isConnected, i, visited);
}
}
return provs;
};
const DFS = (isConnected, i, visited) => {
visited.add(i);
for(let j = 1; j < isConnected.length; j++) {
if(isConnected[i][j] && !(visited.has(j))) {
DFS(isConnected, j, visited);
}
}
}
var findCircleNum = function(isConnected) {
let n = isConnected.length;
if (n==0) return 0;
let visited = {};
let count = 0;
let dfs = (i)=>{
for(let j=0;j<n;j++){
if(isConnected[i][j]==1&&!visited[j]){
visited[j] = true;
dfs(j);
}
}
}
for(let i=0;i<n;i++){
if(!visited[i]){
dfs(i);
count++;
}
}
return count;
};
class Solution {
public int findCircleNum(int[][] isConnected) {
int provinces = isConnected.length;
int[] parent = new int[provinces];
for (int i = 0; i < provinces; i++) {
parent[i] = i;
}
for (int i = 0; i < provinces; i++) {
for (int j = i + 1; j < provinces; j++) {
if (isConnected[i][j] == 1) {
union(parent, i, j);
}
}
}
int circles = 0;
for (int i = 0; i < provinces; i++) {
if (parent[i] == i) {
circles++;
}
}
return circles;
}
public void union(int[] parent, int index1, int index2) {
parent[find(parent, index1)] = find(parent, index2);
}
public int find(int[] parent, int index) {
if (parent[index] != index) {
parent[index] = find(parent, parent[index]);
}
return parent[index];
}
}
DFS
class Solution {
public:
void DFS(int i,int len, vector<vector<int>>& isConnected, vector<int>& visited)
{
for (int j = 0; j < len; ++j)
{
if (i != j && !visited[j] && isConnected[i][j])
{
visited[j] = 1;
DFS(j, len, isConnected, visited);
}
}
}
int findCircleNum(vector<vector<int>>& isConnected) {
int len = isConnected.size();
vector<int>visited(len, 0);
int res = 0;
for (int i = 0; i < len; ++i)
{
if (!visited[i])
{
visited[i] = 1;
DFS(i, len, isConnected, visited);
++res;
}
}
return res;
}
};
时间复杂度:O(N)
空间复杂度:O(N)
https://leetcode-cn.com/problems/number-of-provinces/
DFS/BFS/UnionFind
class UnionFind:
def __init__(self):
self.father = {}
# 额外记录集合的数量
self.num_of_sets = 0
def find(self,x):
root = x
while self.father[root] != None:
root = self.father[root]
while x != root:
original_father = self.father[x]
self.father[x] = root
x = original_father
return root
def merge(self,x,y):
root_x,root_y = self.find(x),self.find(y)
if root_x != root_y:
self.father[root_x] = root_y
# 集合的数量-1
self.num_of_sets -= 1
def add(self,x):
if x not in self.father:
self.father[x] = None
# 集合的数量+1
self.num_of_sets += 1
class Solution:
def findCircleNum(self, M: List[List[int]]) -> int:
uf = UnionFind()
for i in range(len(M)):
uf.add(i)
for j in range(i):
if M[i][j]:
uf.merge(i,j)
return uf.num_of_sets
C++ Code:
class Solution {
public:
void dfs(vector<vector<int>>& isConnected, vector<int>& visited, int provinces, int i) {
for (int j = 0; j < provinces; j++) {
if (isConnected[i][j] == 1 && !visited[j]) {
visited[j] = 1;
dfs(isConnected, visited, provinces, j);
}
}
}
int findCircleNum(vector<vector<int>>& isConnected) {
int provinces = isConnected.size();
vector<int> visited(provinces);
int circles = 0;
for (int i = 0; i < provinces; i++) {
if (!visited[i]) {
dfs(isConnected, visited, provinces, i);
circles++;
}
}
return circles;
}
};
复杂度分析
令 n 为数组长度。
深度优先搜索
class Solution:
def findCircleNum(self, isConnected: List[List[int]]) -> int:
def dfs(i: int):
for j in range(provinces):
if isConnected[i][j] == 1 and j not in visited:
visited.add(j)
dfs(j)
provinces = len(isConnected)
visited = set()
circles = 0
for i in range(provinces):
if i not in visited:
dfs(i)
circles += 1
return circles
# Understand:
1 <= n <= 200
n == isConnected.length
n == isConnected[i].length
isConnected[i][j] is 1 or 0.
isConnected[i][i] == 1
isConnected[i][j] == isConnected[j][i]
# Tests:
Input: isConnected =
[[1,1,0],
[1,1,0],
[0,0,1]]
Output: 2,[1,2],[3]
isConnected = [[1,0,0],[0,1,0],[0,0,1]]
3
[1,0,1],
[0,1,1],
[1,1,1]
return 1
1-3
|
2
union with path compression by rank
if isConnected[i][j] == 1, union(i, j)
return numOfUnions
Time: O(n^2)
Space: O(n), n = isConnected.length
start from each node ([0, n-1]) by a for loop,
- if visited, continue
- if unvisited, mark as visited, explore as many as possible by dfs, increment the count
Time:
O(V + E), V = isConnected.length, E = number of edges = number of 1's in isConnected
E is bounded by n^2
O(n^2)
Space:
stack + visited array
O(V) + O(V)
= O(isConnected.length)
use BFS to start from each node, explore as much as possible, only explore unvisited node
Time: O(V + E) = O(n + n ^ 2) = O(n ^ 2)
Space: O(V) = O(n)
class Solution {
// method 3: BFS
public int findCircleNum(int[][] isConnected) {
Queue<Integer> nodeQueue = new LinkedList<>();
int circleNum = 0;
int n = isConnected.length;
boolean[] visited = new boolean[n];
for (int start = 0; start < n; start++) {
if (!visited[start]) {
nodeQueue.offer(start);
/*
while (!nodeQueue.isEmpty()) {
int size = nodeQueue.size();
for (int i = 0; i < size; i++) {
int curNode = nodeQueue.poll();
visited[curNode] = true;
for (int next = 0; next < isConnected[0].length; next++) {
if (isConnected[curNode][next] == 1 && !visited[next]) {
nodeQueue.offer(next);
}
}
}
}*/
// optimized, no need for the size inner loop
while (!nodeQueue.isEmpty()) {
int curNode = nodeQueue.poll();
visited[curNode] = true;
for (int next = 0; next < isConnected[0].length; next++) {
if (isConnected[curNode][next] == 1 && !visited[next]) {
nodeQueue.offer(next);
}
}
}
circleNum++;
}
}
return circleNum;
}
// method 2: DFS, need review!
public int findCircleNum2(int[][] isConnected) {
int n = isConnected.length;
boolean[] visited = new boolean[n];
int circleNum = 0;
for (int start = 0; start < n; start++) {
if (!visited[start]) {
dfs(start, isConnected, visited);
// each dfs finishes covering as many as nodes
circleNum++;
}
}
return circleNum;
}
private void dfs(int curNode, int[][] isConnected, boolean[] visited) {
visited[curNode] = true;
for (int next = 0; next < isConnected[0].length; next++) {
// second condition guarantees next != cur
if (isConnected[curNode][next] == 1 && !visited[next]) {
dfs(next, isConnected, visited);
}
}
}
// method 1: Union Find
class UF {
int numOfUnions;
int[] size;
int[] parent;
UF(int n) {
numOfUnions = n;
size = new int[n];
parent = new int[n];
for (int i = 0; i < n; i++) {
size[i] = 1;
parent[i] = i;
}
}
boolean isConnected(int p, int q) {
return find(p) == find(q);
}
int find(int x) {
while (parent[x] != x) {
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
void union(int p, int q) {
int representativeOfP = find(p);
int representativeOfQ = find(q);
if (representativeOfP == representativeOfQ) {
return;
}
if (size[representativeOfP] < size[representativeOfQ]) {
size[representativeOfQ] += size[representativeOfP];
parent[representativeOfP] = representativeOfQ;
} else {
size[representativeOfP] += size[representativeOfQ];
parent[representativeOfQ] = representativeOfP;
}
numOfUnions--;
}
}
public int findCircleNum1(int[][] isConnected) {
int n = isConnected.length;
UF unionfind = new UF(n);
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
if (isConnected[i][j] == 1) {
unionfind.union(i, j);
}
}
}
return unionfind.numOfUnions;
}
}
class Solution:
def findCircleNum(self, isConnected: List[List[int]]) -> int:
provinces = len(isConnected)
visited = set()
circles = 0
for i in range(provinces):
if i not in visited:
Q = collections.deque([i])
while Q:
j = Q.popleft()
visited.add(j)
for k in range(provinces):
if isConnected[j][k] == 1 and k not in visited:
Q.append(k)
circles += 1
return circles
class Solution {
public int findCircleNum(int[][] isConnected) {
int n = isConnected.length;
UF uf = new UF(n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (isConnected[i][j] == 1) {
uf.union(i, j);
}
}
}
return uf.size;
}
private static class UF {
int[] parent;
int size;
public UF(int n) {
parent = new int[n];
size = n;
for (int i = 0; i < n; i++) {
parent[i] = i;
}
}
public int find(int x) {
while (parent[x] != x) {
x = parent[x];
}
return x;
}
public void union(int x, int y) {
if (find(x) != find(y)) {
parent[find(x)] = find(y);
size--;
}
}
}
}
const findCircleNum = function(isConnected) {
let visited = new Set, provs = 0;
for(let i = 0; i < isConnected.length; i++) {
if(!(visited.has(i))) {
provs++;
DFS(isConnected, i, visited);
}
}
return provs;
};
const DFS = (isConnected, i, visited) => {
visited.add(i);
for(let j = 1; j < isConnected.length; j++) {
if(isConnected[i][j] && !(visited.has(j))) {
DFS(isConnected, j, visited);
}
}
}
547. 省份数量
入选理由
暂无
题目地址
https://leetcode-cn.com/problems/number-of-provinces/
前置知识
暂无
题目描述