本文主要記錄並查集的基本實現方法,並逐步將一些例題填充到文章中。ide
並查集能夠:
1. 合併集合
2. 查找兩個元素是否在同一個集合內
3. 集合數量
4. 肯定元素屬於哪一個集合。函數
class UF { public: UF(); UF(int N); ~UF(); bool isConnected(int p, int q); int findRoot(int p);//查找根節點 主要函數 void unionSet(int p, int q);//合併集合 主要函數 int getSetCount(); int getElemCount(); private: std::vector<int> m_parent; std::vector<int> m_rank; int m_setCount; //集合個數 int m_elemCount; //元素個數 }; UF::UF() { m_setCount = 0; m_elemCount = 0; } UF::UF(int N): m_setCount(N), m_elemCount(N) { m_parent.resize(N); m_rank.resize(N); for(int i = 0; i < N; ++i) { m_parent[i] = i; m_rank[i] = 1; } } UF::~UF() { } int UF::findRoot( int p ) { if(p != m_parent[p]) { m_parent[p] = findRoot(m_parent[p]); } return m_parent[p]; } void UF::unionSet(int p, int q ) { int rootOfP = findRoot(p); int rootOfQ = findRoot(q); if( rootOfP == rootOfQ ) return ; if(m_rank[rootOfP] > m_rank[rootOfQ]) { m_parent[rootOfQ] = rootOfP; } else { if(m_rank[rootOfP] == m_rank[rootOfQ]) { m_rank[rootOfQ]++; } m_parent[rootOfP] = rootOfQ; } m_setCount--; } bool UF::isConnected( int p, int q) { return findRoot(p) == findRoot(q); }
班上有 N 名學生。其中有些人是朋友,有些則不是。他們的友誼具備是傳遞性。若是已知 A 是 B 的朋友,B 是 C 的朋友,那麼咱們能夠認爲 A 也是 C 的朋友。所謂的朋友圈,是指全部朋友的集合。code
給定一個 N * N 的矩陣 M,表示班級中學生之間的朋友關係。若是M[i][j] = 1,表示已知第 i 個和 j 個學生互爲朋友關係,不然爲不知道。你必須輸出全部學生中的已知的朋友圈總數。leetcode
示例 1:get
輸入:
[[1,1,0],
[1,1,0],
[0,0,1]]
輸出: 2
說明:已知學生0和學生1互爲朋友,他們在一個朋友圈。
第2個學生本身在一個朋友圈。因此返回2。io
示例 2:class
輸入:
[[1,1,0],
[1,1,1],
[0,1,1]]
輸出: 1
說明:已知學生0和學生1互爲朋友,學生1和學生2互爲朋友,因此學生0和學生2也是朋友,因此他們三個在一個朋友圈,返回1。nio
注意:方法
N 在[1,200]的範圍內。
對於全部學生,有M[i][i] = 1。
若是有M[i][j] = 1,則有M[j][i] = 1。集合
class Solution { public: int findCircleNum(vector<vector<int>>& M) { N = M.size(); count = N; parent.resize(count); rank.resize(count); for(int i = 0; i < N; i++) { parent[i] = i; rank[i] = 1; } for(int i = 0; i < N -1 ; ++i) { for(int j = i + 1; j < N; ++j) { if(M[i][j] == 1) { uni(i,j); } } } return count; } int root(int p) { if(p != parent[p]) { parent[p] = root(parent[p]); } return parent[p]; } void uni(int p, int q) { int proot = root(p); int qroot = root(q); if(proot == qroot) return ; if(rank[proot] > rank[qroot]) { parent[qroot] = proot; } else { if(rank[proot] == rank[qroot]) { rank[qroot]++; } parent[proot] = qroot; } count--; } int N; vector<int> parent; vector<int> rank; int count; };
給定一個二維的矩陣,包含 'X' 和 'O'(字母 O)。
找到全部被 'X' 圍繞的區域,並將這些區域裏全部的 'O' 用 'X' 填充。
示例:
X X X X
X O O X
X X O X
X O X X
運行你的函數後,矩陣變爲:
X X X X
X X X X
X X X X
X O X X
解釋:
被圍繞的區間不會存在於邊界上,換句話說,任何邊界上的 'O' 都不會被填充爲 'X'。 任何不在邊界上,或不與邊界上的 'O' 相連的 'O' 最終都會被填充爲 'X'。若是兩個元素在水平或垂直方向相鄰,則稱它們是「相連」的。
class Solution { public: void solve(vector<vector<char>>& board) { if(board.size()==0||board[0].size()==0)return; h = board.size(); w = board[0].size(); len = h*w; parent.resize(len); rank.resize(len); isSide.resize(len); for(int i = 0; i < len; i++) { int x = i/w; int y = i%w; parent[i] = i; rank[i] = 1; if(x == 0 || x == h-1 || y == 0 || y == w-1) { if(board[x][y] == 'O') isSide[i] = true; } else { isSide[i] = false; } } for(int i = 1; i < h; ++i) { for(int j = 1; j < w; ++j) { if(board[i][j-1] == board[i][j]) uni(i*w+j,i*w+j-1); if(board[i-1][j] == board[i][j]) uni(i*w+j,(i-1)*w+j); } } for(int i = 0; i < len; i++) { if(board[i/w][i%w] == 'O' && !isSide[root(i)]) board[i/w][i%w] = 'X'; } } int root(int p) { if(p != parent[p]) { parent[p] = root(parent[p]); } return parent[p]; } void uni(int p, int q) { int proot = root(p); int qroot = root(q); if(proot == qroot) return ; if(rank[proot] > rank[qroot]) { parent[qroot] = proot; } else { if(rank[proot] = rank[qroot]) { rank[qroot]++; } parent[proot] = qroot; } if(isSide[proot]) isSide[qroot] = true; if(isSide[qroot]) isSide[proot] = true; } vector<int> parent; vector<int> rank; vector<bool> isSide; int h; int w; int len; };