leetcode
leetcode 2951 ~ 3000
冗余连接

冗余连接

难度:

标签:

题目描述

English description is not available for the problem. Please switch to Chinese.

代码结果

运行时间: 26 ms, 内存: 16.4 MB


/*
 * 思路:
 * 1. 使用并查集(Union-Find)算法来检测图中的环。
 * 2. 使用Java Stream进行操作。
 * 3. 对边列表进行过滤,找到形成环的最后一条边。
 */

import java.util.stream.IntStream;

public class Solution {
    public int[] findRedundantConnection(int[][] edges) {
        int n = edges.length;
        int[] parent = IntStream.rangeClosed(0, n).toArray();
        
        return IntStream.range(0, n)
                .mapToObj(i -> edges[i])
                .filter(edge -> find(parent, edge[0]) == find(parent, edge[1]) || !union(parent, edge[0], edge[1]))
                .reduce((first, second) -> second) // 获取最后一条冗余边
                .orElse(new int[0]);
    }

    private int find(int[] parent, int x) {
        if (parent[x] != x) {
            parent[x] = find(parent, parent[x]);
        }
        return parent[x];
    }
    
    private boolean union(int[] parent, int x, int y) {
        int rootX = find(parent, x);
        int rootY = find(parent, y);
        if (rootX != rootY) {
            parent[rootX] = rootY;
            return true;
        }
        return false;
    }
}

解释

方法:

该题解使用了并查集的数据结构来找出导致图中出现环的多余边。并查集主要用于处理一些不相交集合的合并及查询问题。这里,每个节点最初指向自己,表示它们各自是一个独立的集合。题解过程中,对于每一条边,使用 find 函数来查找每个顶点的根节点。如果两个顶点的根节点相同,说明添加这条边会形成环,因此这条边就是多余的。否则,通过 merge 函数将这两个顶点所在的集合合并。题目要求返回最后出现在数组中的多余的边,因此在发现多余的边时保存下来,直至所有边检查完毕。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在并查集中,为什么在寻找根节点的过程中要进行路径压缩?这对算法的效率有什么具体影响?
路径压缩是并查集优化技术之一,其目的是减少树的高度,从而使得未来查找根节点的操作更快。在路径压缩过程中,我们使每个访问过的节点直接指向其根节点。这样,经过几次操作后,树的高度大幅度减小,使得任何节点到根节点的路径都将大大缩短,从而提高查找效率。具体来说,路径压缩可以将并查集的时间复杂度几乎降至接近常数时间,这对于处理大量集合合并及查询操作的场景非常关键,显著提升算法性能。
🦆
题解中提到的`按秩合并`没有在代码中明显体现,请问这是否会影响算法的最优性能?如果是,应该如何修改代码以实现按秩合并?
按秩合并是另一种并查集的优化方式,通过记录集合的'秩'(通常是树的高度或者节点数量),并总是将秩较小的集合合并到秩较大的集合上。这样可以避免形成高度不平衡的树,从而进一步优化查找效率。题解没有实现按秩合并,可能会导致树的高度增加,从而影响算法的最优性能。要实现按秩合并,我们可以增加一个数组来记录每个节点的秩,然后在合并时,比较两个根节点的秩,总是将秩较小的树合并到秩较大的树上。如果秩相同,则选择一个作为根,并将其秩加一。
🦆
在题解的`merge`函数中,您是如何处理节点编号的?节点从1开始编号,但似乎在查找函数中处理的是数组索引(从0开始),这之间的转换是否准确?
题解中确实处理了从1开始的节点编号到从0开始的数组索引的转换。在`merge`函数中,每次处理边的时候,用`edges[i][0]`和`edges[i][1]`表示的是从1开始的节点编号,而在查找节点根时,通过`find(m-1)`和`find(n-1)`转换为从0开始的索引。这种转换是准确的,因为数据结构的数组`f`是从0索引开始的,而节点编号从1开始,所以需要减1来对应到正确的数组索引。这样处理确保了节点编号与内部索引之间的一致性。

相关问题