Description:
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.
General Assumption:
People in the even positions of the row are always in their right positions, so if we need to swap, we only swap people in the odd positions.
Solution1:
Analysis:
①To everybody in the row, use DSU to connect him/her and his/her true mate as well as current partner(if a person is in the even position, current partner is the person in his/her right position, if a person is in the odd position, current partner is the person in his/her left position). Just like the illustration shows:
② Find the number of all the connected parts in the graph, we use connectedNumber to denote this number. If all the couples sit together, the number of connected parts is just
r
o
w
.
l
e
n
g
t
h
/
2
row.length / 2
row.length/2. Each time we do a right swap to make couples sit together, the connectedNumber will increase by 1. We do such swap until connectedNumber is equal to
r
o
w
.
l
e
n
g
t
h
/
2
row.length / 2
row.length/2. So the answer of this problem is
r
o
w
.
l
e
n
g
t
h
/
2
row.length / 2
row.length/2 - connectedNumber .
Code:
class Solution {
public int minSwapsCouples(int[] row) {
DSU dsu = new DSU(row.length);
for(int i = 0; i < row.length; i += 2) {
int p1 = row[i];
int p1Mate = (p1 % 2 == 0) ? p1+1 : p1-1;
dsu.union(p1, p1Mate);
int p2 = row[i+1];
int p2Mate = (p2 % 2 == 0) ? p2+1 : p2-1;
dsu.union(p2, p2Mate);
dsu.union(p1, p2);
}
return row.length/2 - dsu.findConnectedPart();
}
}
class DSU {
private int[] parent;
private int[] rank;
public DSU(int n) {
parent = new int[n];
for(int i = 0; i < n; i++){
parent[i] = i;
}
rank = new int[n];
}
public int find(int x) {
if(x != parent[x]) {
parent[x] = find(parent[x]);
}
return parent[x];
}
public void union(int x, int y) {
int xr = find(x);
int yr = find(y);
if(xr == yr) {
return;
}else{
if(rank[xr] < rank[yr]) {
parent[xr] = yr;
}else if(rank[xr] > rank[yr]) {
parent[yr] = xr;
}else{
parent[yr] = xr;
rank[xr]++;
}
}
}
public int findConnectedPart() {
int connectedPart = 0;
for(int i = 0; i < parent.length; i++) {
if(i == parent[i]) {
connectedPart++;
}
}
return connectedPart;
}
}
Solution2:
Analysis:
Use a hashmap to store everyone’s position in the row. To everybody in the even position, if his/her current partner(here current partner means the person in his/her right position) is not his/her true mate, swap his/her current partner and his/her true mate. After each swap, do update the hashmap.
Code:
class Solution {
public int minSwapsCouples(int[] row) {
Map<Integer, Integer> map = new HashMap<>();
for(int i = 0; i < row.length; i++) {
map.put(row[i], i);
}
int swap = 0;
for(int i = 0; i < row.length; i += 2) {
int p1 = row[i];
int p1Mate = (p1 % 2 == 0) ? p1+1: p1-1;
int p2 = row[i+1];
if(p1Mate != p2) {
int temp = row[i+1];
row[i+1] = row[map.get(p1Mate)];
row[map.get(p1Mate)] = temp;
map.put(p2, map.get(p1Mate));
map.put(p1Mate, i+1);
swap++;
}
}
return swap;
}
}