765. Couples Holding Hands
阿新 • • 發佈:2020-08-10
問題:
給定一個座位排表row,
2n 和 2n+1 (n:0,1,2...) 表示一對情侶。
把所有人排放在上述座位排表中。求,要使每一對情侶都坐在一起,要交換多少次座位。
Example 1: Input: row = [0, 2, 1, 3] Output: 1 Explanation: We only need to swap the second (row[1]) and third (row[2]) person. Example 2: Input: row = [3, 2, 0, 1] Output: 0 Explanation: All couples are already seated side by side. Note: len(row) is even and in the range of [4, 60]. row is guaranteed to be a permutation of 0...len(row)-1.
解法:並查集(Disjoint Set)
首先將一對情侶的兩個人組成連通圖。共形成 row.size/2 個連通圖。
然後,從座位排表中,兩兩取出,應該坐在一起的兩個位置。
將這兩個位置上,當前坐的人連線起來merge。
最終形成 X 個連通圖。
對每個連通圖,代表:應該內部交換位置,使得情侶坐在一起。
★每交換一次,能夠促成一對情侶相鄰坐好,
這裡若進行一次解偶,獨立這一對情侶的連通圖。
依此類推操作後,最終若形成 N 個連通圖(即N對情侶),
其中,共進行解偶了,N-1 次(一個連通圖 變成 N個連通圖),促成 N-1 對情侶相鄰(餘下最後一對自然相鄰)
由於★,也就是,共交換座位了 N-1 次。
那麼,所有的連通圖,共交換row.size/2 - X 次。
程式碼參考:
1 class Solution { 2 public: 3 int minSwapsCouples(vector<int>& row) { 4 DisjointSet DS(row.size()); 5 for(int i=1; i<row.size(); i+=2) { 6 DS.merge(i, i-1); 7 } 8 for(int i=1; i<row.size(); i+=2) { 9 DS.merge(row[i], row[i-1]); 10 } 11 return row.size() / 2 - DS.getGroupCount(); 12 } 13 };
並查集類,程式碼參考:
1 class DisjointSet { 2 public: 3 DisjointSet(int n):root(n,0), rank(n,0) { 4 for(int i=0; i<n; i++) { 5 root[i]=i; 6 } 7 } 8 int find(int i) { 9 if(root[i]!=i) { 10 root[i] = find(root[i]); 11 } 12 return root[i]; 13 } 14 bool merge(int x, int y) { 15 int x_root=find(x); 16 int y_root=find(y); 17 if(x_root==y_root) return false; 18 if(rank[x_root] > rank[y_root]) { 19 root[y_root] = x_root; 20 } else if(rank[y_root] > rank[x_root]) { 21 root[x_root] = y_root; 22 } else { 23 root[y_root] = x_root; 24 rank[x_root]++; 25 } 26 return true; 27 } 28 int getGroupCount() { 29 int res=0; 30 for(int i=0; i<root.size(); i++) { 31 if(root[i] == i) res++; 32 } 33 return res; 34 } 35 private: 36 vector<int> root; 37 vector<int> rank; 38 };