1. 程式人生 > 其它 >Linux Python專案常用指令

Linux Python專案常用指令

技術標籤:LeetCode刷題

547. 省份數量

連結:https://leetcode-cn.com/problems/number-of-provinces/

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]10
  • isConnected[i][i] == 1
  • isConnected[i][j] == isConnected[j][i]

思路:是一個很明顯的並查集問題,開始時是n個獨立的集合,每合併一次,集合數就減少1。我們用路徑壓縮排行優化(增加按秩合併也可以,但是如果時間不是卡的特別死,按秩合併的優化力度有限,反而會提高程式碼複雜度)。

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;
    }
};

增加按秩合併版:

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;
    }
};

這種寫法是為了保證Rank正確反映樹的高度,但同時過於複雜的if-else語句是會降低程式執行效能的,如果我們不需要保證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;
                ++ 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;
    }
};