Leetcode 765. Couples Holding Hands
Problem:
N couples sit in 2N seats arranged in a row and want to hold hands. We want to know the minimum number of swaps so that every couple is sitting side by side. A swap consists of choosing any two people, then they stand up and switch seats.
The people and seats are represented by an integer from 0
to 2N-1
, the couples are numbered in order, the first couple being (0, 1)
, the second couple being (2, 3)
, and so on with the last couple being (2N-2, 2N-1)
.
The couples' initial seating is given by row[i]
being the value of the person who is initially sitting in the i-th seat.
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 of0...len(row)-1
.
题目大意就不解读了,对于这道题可以用greedy和Union Find两种解法,代码很简单就不细说了。我认为这道题之所以为hard是因为很难去解读这道题,这道题能用greedy的默认前提是我们保证每次交换都至少能凑成一组,而且这一定是最优情况,事实上我们很难去验证这种解法的正确性(虽然对于这道题它确实是正确的),对于greedy算法的我们或多或少总会有这样的疑惑。所谓的Union Find解法,其实也是建立在greedy的基础之上,他把row[i]划分为row[i]/2组去构建一张图,每个节点的入度和出度之和为2,通过Union每对row[i]和row[i+1]之后可以获得若干个块,而对于每个块,则我们可以肯定它必然是一个环(因为每个节点的度为2,不可能画得出一张图使得度全是2还不能构成一个大环的),因此我们可以理解为同一个块中的每条边为一次交换,而最后一次交换会使两个组分好,所以交换次数为edges-1。计算所有的块的edges-1之和即最后结果。我们可以观察到其实Union Find和greedy没有本质区别,Union Find其实并不是真的去对数组操作进行交换,而是通过图来保存是否需要交换这一信息,它默认若两个人不是夫妻就必然交换一次且只需要交换一次。
0
/ \
1 2 -> [0,2,3,6,7,4,5,1]
\ /
3
如上面这个例子,右边的数组可以得到左边的这张分组关系图,我们可以得知[0,1],[1,3],[3,2]之间交换一次即可分组成功,最后一条边不用交换。
Code:
1 class Solution { 2 public: 3 int Find(vector<int> &parent,int target){ 4 if(parent[target] == target) 5 return target; 6 return Find(parent,parent[target]); 7 } 8 bool Union(vector<int> &parent,vector<int> &rank,int v1,int v2){ 9 int p1 = Find(parent,v1); 10 int p2 = Find(parent,v2); 11 if(p1 == p2) return false; 12 if(rank[p1] > rank[p2]) parent[p2] = p1; 13 else if(rank[p1] < rank[p2]) parent[p1] = p2; 14 else{ 15 parent[p2] = p1; 16 rank[p1]++; 17 } 18 return true; 19 } 20 int minSwapsCouples(vector<int>& row) { 21 int result = 0; 22 int m = row.size(); 23 vector<int> parent(m); 24 vector<int> rank(m,0); 25 for(int i = 0;i != m;++i) 26 parent[i] = i; 27 for(int i = 0;i != m;i+=2){ 28 if(Union(parent,rank,row[i]/2,row[i+1]/2)){ 29 result++; 30 } 31 } 32 return result; 33 } 34 };
1 class Solution { 2 public: 3 int minSwapsCouples(vector<int>& row) { 4 int m = row.size(); 5 int result = 0; 6 unordered_map<int,int> um; 7 for(int i = 0;i != m;++i) 8 um[row[i]] = i; 9 for(int i = 0;i != m;i+=2){ 10 int partner = (row[i]%2 == 0) ? (row[i]+1) : (row[i]-1); 11 if(row[i+1] == partner) continue; 12 result++; 13 int index = um[partner]; 14 um[row[i+1]] = index; 15 um[row[index]] = i+1; 16 swap(row[i+1],row[index]); 17 } 18 return result; 19 } 20 };