1. 程式人生 > 其它 >leetcode-情侶牽手(初識並查集)

leetcode-情侶牽手(初識並查集)

技術標籤:java演算法

情侶牽手(並查集)

題目

  1. 情侶牽手
    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]的位置即可。

示例 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--; } } }