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:

  1. len(row) is even and in the range of [4, 60].
  2. row is guaranteed to be a permutation of 0...len(row)-1.

 

Solution:

  题目大意就不解读了,对于这道题可以用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 };

 

posted on 2019-01-05 15:07  周浩炜  阅读(225)  评论(0编辑  收藏  举报

导航