国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Leetcode之Union-Find(并查集)

roland_reed / 2381人閱讀

摘要:并查集包括查詢和聯(lián)合,主要使用不相交集合查詢主要是用來決定不同的成員是否在一個(gè)子集合之內(nèi)聯(lián)合主要是用來把多個(gè)子集合成一個(gè)集合的實(shí)際運(yùn)用計(jì)算機(jī)網(wǎng)絡(luò)檢查集群是否聯(lián)通電路板檢查不同的電路元件是否聯(lián)通初始化聯(lián)通與檢測與是否聯(lián)通返回聯(lián)通的數(shù)

并查集(Union-Find)包括查詢(Find)和聯(lián)合(Union),主要使用不相交集合(Disjoint-Sets)
查詢(Find)主要是用來決定不同的成員是否在一個(gè)子集合之內(nèi)
聯(lián)合(Union)主要是用來把多個(gè)子集合成一個(gè)集合
Union-Find的實(shí)際運(yùn)用:
1.計(jì)算機(jī)網(wǎng)絡(luò)檢查集群是否聯(lián)通 2.電路板檢查不同的電路元件是否聯(lián)通

Union-Find(mainly used for detection of connectivity problem):

Public Class UF:
    UF(int n) //初始化(abstract N sites : list of integers to 0,1,2 .. N-1)
    Void Union(int a, int b) //聯(lián)通a與b(add connection between a and b)
    int find(int a) //component identifier
    boolean isConnected(int a, int b) //檢測a與b是否聯(lián)通
    int count() //返回聯(lián)通的數(shù)量(return number of connected components)

舉個(gè)例子:
Given Objects: 0, 1, 2, 3, 4, 5
union(0, 1):
0-1, 2, 3, 4, 5
union(1,3):
0-1-3, 2, 4, 5
union(2,5):
0-1-3, 2-5, 4
union(3, 5):
0-1-3-2-5, 4

Union-Find在計(jì)算機(jī)算法面試主要用來解決動態(tài)圖(Dynamic Graph)的一系列問題:
例如: 一個(gè)由0與1組成的二維矩陣,0可以看成海洋,1可以看成陸地
110101
001011
101011
100110
Q1:有多少島?4(dfs,bfs),靜態(tài)圖(static graph)
Q2:湖(上下左右不包換對角線被陸地包圍)的面積有多少? 2(dfs, bfs),靜態(tài)圖
Q3:如果改變圖中的元素有多少島?(0,0):5; (0,1):5; (0, 5): 6; (1,5): 5, 動態(tài)圖(Dynamic Graph)

Union-Find的種類:
Quick UnionFind(Quick-Union)

class QuickUnion:
    private int[] ids;
    public QuickUnionFind(int n):
        ids = new int[n];
        for(int i = 0; i < n; i++) {
            ids[i] = i;
        }
    }
    public void union(int a, int b) {
        int idA = ids[a];
        int idB = ids[b];
        for(int i = 0; i < n; i++) {
            if(ids[i] == idB){ //聯(lián)通所有與A聯(lián)通的元素
                ids[i] = idA;
            }
        }
    }
    public boolean find(int a, int b) {
        return ids[a] == ids[b];
    }
 }

比如,如果想要連通id[5]與id[9], 需要在union的過程中遍歷所有與id5連通的元素將下標(biāo)改成id9,或者將所有id9的下標(biāo)改成id5

QuickUnion的遍歷需要通過一次的數(shù)組讀取來找到對應(yīng)的節(jié)點(diǎn),但是對于新增路徑需要需要線性時(shí)間找到對應(yīng)的組號進(jìn)行修改,所以對于大數(shù)據(jù)量來說如果新增路徑數(shù)量是M,節(jié)點(diǎn)的數(shù)量是N,我們需要O(MN)的時(shí)間復(fù)雜度來尋找對應(yīng)的標(biāo)號然后修改,平方的時(shí)間復(fù)雜度是非常費(fèi)時(shí)的,所以我們需要提高Union的效率

Tree Union Find
QuickUnion之所以Union的時(shí)間復(fù)雜度比較高主要是因?yàn)閷τ诿總€(gè)節(jié)點(diǎn)的所屬的組都是多帶帶記錄,因此需要一種更優(yōu)化的數(shù)據(jù)結(jié)構(gòu)來快速更新節(jié)點(diǎn)所屬的組,因此我們可以用一個(gè)parent node來連接所有的sub node形成樹來降低Union的時(shí)間

使用parent-link將子節(jié)點(diǎn)與根節(jié)點(diǎn)連接,id[a]的值就是父節(jié)點(diǎn)的序號,因此通過查找,總可以從一個(gè)子節(jié)點(diǎn)查找到根節(jié)點(diǎn)(id[a] == a),因此在處理不同組的時(shí)候,我們只需要找到每個(gè)元素的根節(jié)點(diǎn)然后更新根節(jié)點(diǎn)的指向就可以了,就相當(dāng)于將其中一個(gè)根節(jié)點(diǎn)所代表的樹變成另外一個(gè)根節(jié)點(diǎn)的子樹

class TreeUnionFind:
    private int[] ids;
    public TreeUnionFind(int n) {
        ids = new int[n];
        for(int i = 0; i < n; i++) {
            ids[i] = i;
        }
    }
    public int root(int a) {
        int root = a;
        while(ids[root] != root) {
                ids[root] = root;
        }
    }
    public boolean find(int a, int b) {
        return root(a) == root(b);
    }
    public void union(int a, int b) {
        int rootA = ids[a];
        int rootB = ids[b];
        ids[rootA] = rootB;
    }
}

但是樹這種數(shù)據(jù)結(jié)果經(jīng)常會根據(jù)輸入數(shù)據(jù)本身的性質(zhì)而變化,如果輸入數(shù)據(jù)是有序的相對應(yīng)的樹會變成一個(gè)單一鏈表因而不具備范性的運(yùn)用情況

Weighted Quick Union Find

根據(jù)Quick-Union Find:

    public void union(int a, int b) {
        int idA = ids[a];
        int idB = ids[b];
        for(int i = 0; i < n; i++) {
            if(ids[i] == idB){ 
                ids[i] = idA;
            }
        }
    }

ids[i] = idA是一種hard code的習(xí)慣,因?yàn)閞andom assign一棵樹是另外一棵樹的子樹沒有考慮輸入數(shù)據(jù)的規(guī)模,如果輸入數(shù)據(jù)p與q, 如果p數(shù)據(jù)所在樹的規(guī)模比q數(shù)據(jù)所在樹的規(guī)模大得多,p與q新形成的樹不是平衡樹

因此,需要總是需要用小的size的樹與大的size的樹合并從而盡量達(dá)到樹的平衡

class WeightedQuickUnionFind{
    private int[] ids;
    private int[] sizes;
    public WeightedQuickUnionFind(int n) {
        ids = new int[n];
        sizes = new int[n]; //在quickUnion的基礎(chǔ)上增加一個(gè)記錄size的變量
        for(int i = 0; i < n; i++) {
            ids[i] = i;
            sizes[i] = 1;//初始化size的大小為1
        }
    }
    public int root(int a, int b) {
        int root = a;
        while(ids[root] != root) {
            root = ids[root];
        }
        return root;
    }
    public void union(int a, int b) {
        int rootA = ids[a];
        int rootB = ids[b];
        if(sizes[rootA] > sizes[rootB]) { //判斷size的大小來更新root
            ids[rootB] = rootA;
            sizes[rootA] += sizes[rootB];
        } else {
            ids[rootA] = rootB;
            sizes[rootB] += sizes[rootA];
        } 
    }
 }        

通過weightedQuickUnion, 可以通過O(logn)的時(shí)間復(fù)雜度來分別Union和Find所需要的元素

Weighted QuickUnion With Path Compression
在Weighted QuickUnion的基礎(chǔ)上我們可以通過路徑壓縮(path compression)就是把所有的元素下標(biāo)直接連接到父節(jié)點(diǎn)來達(dá)到降低Union和Find時(shí)間復(fù)雜度的目的

class weightedQuickUnionWithPathCompression{
    private int[] ids;
    private int[] sizes;
    public weightedQuickUnionWithPathCompression(int n) {
        ids = new int[n];
        sizes = new int[n];
        for(int i = 0; i < n; i++) {
            ids[i] = i;
            sizes[i] = 1;
        }
    }
    public int root(int a, int b) {
        int root = a;
        while(ids[root] != root) {
            root = ids[root];
        }
        while(a != root) { //connect sub element directly to root
            int temp = ids[a];
            ids[a] = root;
            a = temp;
        }
        return root;
    }
    public boolean find(int a, int b) {
        return root(a) == root(b);
    }
    public boolean union(int a, int b) {
        int rootA = ids[a];
        int rootB = ids[b];
        if(sizes[rootA] > sizes[rootB]) {
            ids[rootB] = rootA;
            sizes[rootA] += sizes[rootB];
        } else {
            ids[rootA] = ids[rootB];
            sizes[rootB] += sizes[rootA];
        }
    }
 }

由此,以上就是所有關(guān)于動態(tài)連接的UnionFind的介紹,下圖是不同思路并查集的算法時(shí)間復(fù)雜度對比:
Algorithm
Quick UnionFind: Construct: O(n); Find: O(1); Union:O(n)
Tree UnionFind: Construct: O(n); Find: O(tree height); Union:O(n)
Weighted QuickUnionFind:Construct: O(n); Find: O(logn); Union:O(logn)
Weighted QuickUnionFind with Path Compression: Construct: O(n); Find: amortizedO(1); Union:amortizedO(1)

leetcode里使用UnionFind的題主要有:Number of Islands(lc200), LongestConsecutiveSequence(lc128), SurroundedRegion(lc130)

Surrounded Region:
Given a 2D board containing "X" and "O" (the letter O), capture all regions surrounded by "X".A region is captured by flipping all "O"s into "X"s in that surrounded region.
For Example:
XXXX
XOOX
XXOX
XOXX
After should become:
XXXX
XXXX
XXXX
XOXX

class Solution{
    public void solve(char[][] board) {
        //sanity check
        if(board == null || board.length == 0) return;
        int row = board.length;
        int col = board[0].length;
        int dummy = row * col; //create a dummy node to represent list of nodes
        UnionFind uf = new UnionFind(row * col + 1);
        for(int i = 0; i < row; i++) {
            for(int j = 0; j < col; j++) {
                if(board[i][j] == "O") {
                    if(i == 0 || i == row - 1 || j == 0 || j == col - 1) {
                        uf.union(node(i, j), dummy); //connect corner nodes
                    } else {
                        if(i > 0 && board[i-1][j] == "O") uf.union(node(i, j), node(i-1, j));
                        if(i > 0 && board[i+1][j] == "O") uf.union(node(i, j), node(i-1, j));
                        if(j > 0 && board[i][j-1] == "O") uf.union(node(i, j), node(i, j-1));
                        if(j > 0 && board[i][j+1] == "O") uf.union(node(i, j), node(i, j+1));
                    }
                }
            }
         }
         for(int i = 0; i < row; i++) {
             for(int j = 0; j < col; j++) {
                 if(uf.isConnected(board[i][j], dummy)) board[i][j] = "O";
                 else board[i][j] = "X";
             }
         }
      }
      public int node(int i, int j) {
          return i * col + j;//convert 2d dimension to 1d
      }
 }
 class UnionFind{
     int[] parents;
     public UnionFind(int[] n) {
         parents = new int[n];
         for(int i = 0; i < n; i++) {
             parents[i] = i;
         }
     }
     public void union(int i, int j) {
         int rootA = find(i);
         int rootB = find(j);
         if(rootA != rootB) {
             parents[rootA] = rootB;
         }
     }
     public int find(int node) {
         if(parents[node] == node) return node;
         parents[node] = find(parents[node]);
         return parents[node];
     }
     public boolean isConnected(int n1, int n2) {
         return find(n1) == find(n2);
     }
}



References:
1.https://algs4.cs.princeton.ed...

2.http://blog.csdn.net/dm_vince...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/68283.html

相關(guān)文章

  • leetcode200. Number of Islands

    摘要:題目要求提供一個(gè)二維數(shù)組表示一張地圖,其中代表陸地,代表海洋。這里使用一個(gè)新的二維數(shù)組來表示對應(yīng)地圖上的元素屬于哪個(gè)并查集。在合并的時(shí)候先進(jìn)行判斷,如果二者為已經(jīng)相連的陸地,則無需合并,否則將新的二維數(shù)組上的元素指向所在的并查集。 題目要求 Given a 2d grid map of 1s (land) and 0s (water), count the number of isla...

    Zoom 評論0 收藏0
  • Union-Find查集算法學(xué)習(xí)筆記

    摘要:算法鏈接學(xué)習(xí)工具,,環(huán)境搭建在小伙伴的推薦下,這個(gè)學(xué)期開始上普林斯頓的算法課。一系列的整數(shù)對代表與相互連接,比如等,每一個(gè)整數(shù)代表了一個(gè)。我覺得這個(gè)可能也是并查集相關(guān)應(yīng)用。這學(xué)期繼續(xù)學(xué)習(xí)深入理解了就能明白了。 《算法》鏈接:1.5 Case Study: Union-Find學(xué)習(xí)工具:mac,java8,eclipse,coursera 環(huán)境搭建在小伙伴的推薦下,這個(gè)學(xué)期開始上普林斯頓...

    hzc 評論0 收藏0
  • [Leetcode] Graph Valid Tree 圖與樹

    摘要:這樣就將一個(gè)集合的節(jié)點(diǎn)歸屬到同一個(gè)集合號下了。最后如果并查集中只有一個(gè)集合,則說明可以構(gòu)建樹。 Graph Valid Tree Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), write a function to check w...

    luqiuwen 評論0 收藏0
  • Tensorflow代碼解析(四)

    摘要:聯(lián)合查找算法是并查集數(shù)據(jù)結(jié)構(gòu)一種應(yīng)用。并查集是一種樹型的數(shù)據(jù)結(jié)構(gòu),其保持著用于處理一些不相交集合的合并及查詢問題。的特征是刪除節(jié)點(diǎn)。目前就職于騰訊事業(yè)部,從事神經(jīng)機(jī)器翻譯工作。 5. TF - Graph模塊TF把神經(jīng)網(wǎng)絡(luò)模型表達(dá)成一張拓?fù)浣Y(jié)構(gòu)的Graph,Graph中的一個(gè)節(jié)點(diǎn)表示一種計(jì)算算子。Graph從輸入到輸出的Tensor數(shù)據(jù)流動完成了一個(gè)運(yùn)算過程,這是對類似概率圖、神經(jīng)網(wǎng)絡(luò)等連接...

    馬龍駒 評論0 收藏0
  • [Leetcode] Graph Valid Tree 判斷一個(gè)圖是否為樹

    摘要:只有一個(gè)連通分量還沒有環(huán),就是樹,無根樹。無向圖邊的兩端是對稱的,無向圖講究連通這個(gè)概念,沒有方向,沒有拓?fù)洌芟窦希苑浅_m合用并查集來解決。并查集寫法參考注意方法用找的老大哥,合并的是的老大哥。 Graph Valid Tree Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each...

    xbynet 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<