力扣打卡 765-情侣牵手(并查集)

Problem: 765. 情侣牵手

思路

模拟一次四对情侣的换位
力扣打卡 765-情侣牵手(并查集)_第1张图片

这次换位的位置指向具有首尾相连的特点,也就是说四对情侣(或者说座位)在一个连通分量内,每一次换位都能促成一对情侣成功牵手,因此需要交换3次(3对情侣都找到了配偶那剩下的一定找到了配偶)。
力扣打卡 765-情侣牵手(并查集)_第2张图片

要求输出最少交换次数,假设有N对情侣,逻辑上能相连(也就是在一个连通分量里)的情侣为:N1,N2,…,Nn,(n就是换位前的连通分量数)并且N1 + N2 +…+ Nn = N。

由上面的例子可以知道,找到正确的配偶后,座位其实就成为了一个独立的连通分量,这种独立的连通分量就是我们所希望得到的
找位置其实就是要将逻辑上连在一起的情侣这种连通分量拆开为一个个独立的目标连通分量

引用力扣题解的图:
力扣打卡 765-情侣牵手(并查集)_第3张图片
要完成这项工作,每个连通分量至少需要交换N1 - 1,N2 -1,…,Nn - 1次。
初始已经坐在一起的情侣无需交换,本身就是目标的连通分量之一。
将每个连通分量的最小交换的次数求和:
(N1 - 1) + (N2 - 1) + … + (Nn - 1) = N - n
翻译一下就是:最少交换次数 = 所有情侣对数(目标连通分量) - 换位前的连通分量数

解题方法

在推出最少交换次数 = 所有情侣对数(目标连通分量) - 换位前的连通分量数这个逻辑之后,使用并查集就可以推出答案,但是在合并时需要注意相邻的数字必须跳过合并,不能对已经坐在一起的情侣进行换位。

复杂度

  • 时间复杂度:
    O ( n l o g n ) O(nlogn) O(nlogn) n为输入数组的长度

  • 空间复杂度:
    O ( n ) O(n) O(n) 并查集底层用到的数组长度为n/2

Code

public 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--;
        }
    }
}

你可能感兴趣的:(leetcode,算法)