The sword refers to offer116: the number of provinces

Question:
There are n cities, some of which are connected to each other and some of which are not. If city a is directly connected to city b, and city b is directly connected to city c, then city a is indirectly connected to city c.
A province is a group of directly or indirectly connected cities, excluding other unconnected cities.
You are given an nxn matrix isConnected, where isConnected[i][j] = 1 means that the ith city is directly connected to the jth city, and isConnected[i][j] = 0 means that the two are not directly connected.
Returns the number of provinces in the matrix.

Example 1:
insert image description here
Input: isConnected = [[1,1,0],[1,1,0],[0,0,1]]
Output: 2
Example 2:
insert image description here
Input: isConnected = [[1,0,0] ,[0,1,0],[0,0,1]]
Output: 3

Analysis:
The first solution:
the search algorithm of the graph can be used to calculate the number of subgraphs in the graph. Scan all nodes in the graph. If a node v has not been visited before, search its subgraph, and when all nodes have been visited, you can know how many subgraphs there are in the graph.
Both breadth-first search and depth-first search can be used to calculate the number of subgraphs in a graph. This problem takes breadth-first traversal as an example.
If the node corresponding to a city i has not been visited before, call the function findCircle to access all nodes in the subgraph corresponding to the city circle in which it is located, and the variable result records the number of city circles. Each time a subgraph corresponding to a circle of friends is visited, the result is added 1.
If there are n cities, then the graph has n nodes and O(n^2) edges, and the time complexity of breadth-first search is O(n^2).
The second solution:
apply union search to solve the problem. (For specific operations, see the comments)
Create an array fathers of length n to store the parent nodes of n nodes. With this array fathers, if you want to know the root node of the subset where node i is located, you can start from node i and point to the parent node along the way The pointer search for , the time complexity appears to be O(n), but the path from node i to the root node can be compressed, thus optimizing time efficiency.

Code:

package com.kuang;

import sun.java2d.opengl.OGLRenderQueue;

import java.util.LinkedList;
import java.util.Queue;

public class FindCircleNum {
    
    
    public int findCircleNum1(int[][] isConnected) {
    
    
        boolean[] visited = new boolean[isConnected.length];
        int result = 0;
        for (int i = 0; i < isConnected.length; i++) {
    
    
            if (!visited[i]){
    
    
                findCircle(isConnected,visited,i);
                result++;
            }
        }
        return result;
    }

    private void findCircle(int[][] isConnected, boolean[] visited, int i) {
    
    
        Queue<Integer> queue = new LinkedList<>();
        queue.add(i);
        visited[i] = true;
        while (!queue.isEmpty()){
    
    
            int t = queue.remove();
            for (int friend = 0; friend < isConnected.length; friend++) {
    
    
               if (isConnected[t][friend]==1 && !visited[friend]){
    
    
                   queue.add(friend);
                   visited[friend] = true;
               }
            }
        }
    }
}

insert image description here

package com.kuang;

public class FindCircleNum2 {
    
    
    public int findCircleNum(int[][] M){
    
    
//        数组fathers用来记录每个节点的根节点,如果班级中有n个学生,那么n个节点被初始化
//        为n个互不连通的子图,在并查集中每个节点的父节点指针都指向自己
        int[] fathers = new int[M.length];
        for (int i = 0; i < fathers.length; i++) {
    
    
            fathers[i] = i;
        }
        int count = M.length;
        for (int i = 0; i < M.length; i++) {
    
    
            for (int j = i+1; j < M.length; j++) {
    
    
//                i,j互为朋友,调用union在必要时合并他们的圈
                if (M[i][j] ==1 && union(fathers,i,j)){
    
    
//                    每当两个子集合并成一个子集,子集数目减1,相应地朋友圈也减1
                    count--;
                }
            }
        }
        return count;
    }
    private boolean union(int[] fathers,int i, int j){
    
    
        int fatherOfI = findFather(fathers,i);
        int fatherOfJ = findFather(fathers,j);
//        判断节点i和节点j的根节点是否相同
        if (fatherOfI != fatherOfJ){
    
    
//            如果把fathers[i]设为j,就相当于把整个第一个子图挂在节点j下,也就是合并两个子图
            fathers[fatherOfI] = fatherOfJ;
            return true;
        }
//        节点i和节点j根节点相同,它们已经位于同一个子集中,那么它们对应的两个学生已经在同一个圈里了,
//        也就没必要合并,此时直接返回false
        return false;
    }
//用来查找一个节点的根节点,一旦得知节点i的根节点就记录到father[i]中,就相当于压缩了路径
    private int findFather(int[] fathers, int i) {
    
    
        if (fathers[i] != i){
    
    
            fathers[i] = findFather(fathers,fathers[i]);
        }
        return fathers[i];
    }
}

Guess you like

Origin blog.csdn.net/Jiaodaqiaobiluo/article/details/124040512