並查集(小米麵試題求朋友圈的個數)
阿新 • • 發佈:2019-02-11
(一)並查集的引入
以小米的這道題為例
並查集定義:並查集實際上是右一個數組實現的,這個陣列比較特殊,最開始將陣列的每一個數據看成一個單獨的集合,用-1表示。然後根據題目要求1和2可以合併,將第2個數據合併到1上時,array[1]+=array[2],array[2]=1(陣列的array[1]儲存其與array[2]累加的值,這個值為負,array[2]儲存他合併到的那個結點)
通過並查集儲存過後的資料如上圖所示,那麼最後只需要計數陣列中負數的個數就是朋友圈的個數。
(二)實現程式碼
由於面試的時候有兩種選擇,使用類或直接用函式實現,我這裡給出兩種方式的程式碼:
1.使用C++類:
測試時包上標頭檔案即可
class UnionFindSet { private: int *_array; size_t _size; public: UnionFindSet() :_array(NULL) , _size(0) {} UnionFindSet(int size) :_array(new int[size]) , _size(size) { memset(_array, -1, sizeof(size_t)*size); } int FindRoot(int child) { if (_array[child] > 0) { return _array[child]; } else { return child; } } void Combine(int child1, int child2) { int root1 = FindRoot(child1); int root2 = FindRoot(child2); _array[root1] += _array[root2]; _array[root2] = root1; } int FriendCount() { int count=0; for (int i = 0; i <_size; i++) { if (_array[i] < 0) { count++; } } return count; } }; int Friends(int n, int m, int r[][2]) { UnionFindSet FindFriends(n); for (int i = 0; i < m; i++) { FindFriends.Combine(r[i][0], r[i][1]); } int friendsCount = FindFriends.FriendCount()-1; cout << "一共有" << friendsCount << "個朋友圈"<<endl; return friendsCount; } void Test() { int r[3][2] = { 1, 2, 2, 3, 4, 5 }; Friends(5, 3, r); }
2.直接C++寫函式
# include<iostream> using namespace std; # include"UnionFindSet.h" //不寫類實現並查集方法求朋友圈個數 int FindRoot(int *&array, int child) { if (array[child] > 0) { return array[child]; } else { return child; } } int FriendsCount(int n,int m,int r[][2]) { int*array = new int[n]; memset(array, -1, sizeof(int)*n); for (int i = 0; i < m; i++)//合併兩個集合 { int root1 = FindRoot(array,r[i][0]); int root2 = FindRoot(array,r[i][1]); array[root1] += array[root2]; array[root2] = root1; } int count = 0; for (int i = 0; i < n; i++) { if (array[i] < 0) { count++; } } cout << "朋友圈的個數為:" << count - 1 << endl; return count - 1; } int main() { int r[3][2] = { 1, 2, 2, 3, 4, 5 }; FriendsCount(5, 3, r); }