leetcode-情侶牽手(初識並查集)
阿新 • • 發佈:2021-02-15
情侶牽手(並查集)
題目
- 情侶牽手
N 對情侶坐在連續排列的 2N 個座位上,想要牽到對方的手。 計算最少交換座位的次數,以便每對情侶可以並肩坐在一起。 一次交換可選擇任意兩人,讓他們站起來交換座位。
人和座位用 0 到 2N-1 的整數表示,情侶們按順序編號,第一對是 (0, 1),第二對是 (2, 3),以此類推,最後一對是 (2N-2, 2N-1)。
這些情侶的初始座位 row[i] 是由最初始坐在第 i 個座位上的人決定的。
示例 1:
輸入: row = [0, 2, 1, 3]
輸出: 1
解釋: 我們只需要交換row[1]和row[2]的位置即可。
輸入: row = [3, 2, 0, 1]
輸出: 0
解釋: 無需交換座位,所有的情侶都已經可以手牽手了。
說明:
len(row) 是偶數且數值在 [4, 60]範圍內。
可以保證row 是序列 0…len(row)-1 的一個全排列。
思路
並查集的套路:
合併擁有同一個領導的節點
find方法:尋找當前節點的領導,最大的那個!皇上!
union方法:合併2個節點(如果本身就是一個皇上,不合並,否則任意合併)
初始化:先讓每個節點都是自己的皇上
該題目的套路:最小交換次數 = 最終連通數量 - 已有連通數
最終連通數量就是N/2
已有連通數 = 最終的連通量 - 手動合併的連通量
row[i] 和 row[i+1] 如果真的是相鄰的,這兩個值應該只差1,/2的值必然一致
程式碼
class Solution {
// 尋找裡面連通分量的個數
public int minSwapsCouples(int[] row) {
int len = row.length;
int N = len / 2;
UnionFind unionFind = new UnionFind(N);
for (int i = 0;i < len;i+=2) {
unionFind.union(row[i]/2, row[i+1]/2);
}
return N - unionFind.getCount();
}
private class UnionFind {
private int[] parent;
private int count;
public int getCount() {
return count;
}
public UnionFind(int n) {
this.count = n;
this.parent = new int[n];
for (int i = 0;i < n;i++) {
parent[i] = i;
}
}
public int find(int x) {
while (x != parent[x]) {
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
public void union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX == rootY) {
return;
}
parent[rootX] = rootY;
count--;
}
}
}