【LeetCode每日一题】685. 冗余连接 II

【LeetCode每日一题】685. 冗余连接 II

685. 冗余连接 II

题目来源link
算法思想:树,深度优先遍历,有向图,并查集;

输入一个有向图,该图由一个有着N个节点 (节点值不重复1, 2, …, N) 的树及一条附加的边构成。附加的边的两个顶点包含在1到N中间,这条附加的边不属于树中已存在的边
在这里插入图片描述

题目分析

分析来源link
定义:
冲突边:导致一个节点有两个父节点的边,如[[2,1],[3,1]],[3,1]则保存为冲突边。
成环边:导致产生环的边,如[[1,2],[2,3],[3,1]],[3,1]则保存为成环边。
所有情况分析:
1.无冲突,有环:无冲突,则直接返回成环边
例子:[[1,2], [2,3], [3,4], [4,1], [1,5]],此时[4,1]会产生环,但不产生冲突。
在这里插入图片描述
2.无环,有冲突:无环,则直接返回冲突边,即[u,v]
例子: [[1,2], [1,3], [2,3]],此时[2,3]会产生冲突,但不产生环。
在这里插入图片描述
3.有冲突,有环:这种情况下要保留冲突边,因为环的影响更优先于冲突,那么去掉环之中会导致冲突的那条边,即[parent[v],v]
例子:[[2,1],[3,1],[1,4],[4,2]],此时[3,1]产生冲突,[4,2]产生环,要保留冲突边[3,1],通过找到1的父节点,从而获得环之中的冲突边:[2,1]
在这里插入图片描述

数据结构–并查集

简述:一种快速获取两者是否存在于同一集合的数据结构,False则合并这两个集合,在这题中,True则表示成环。

java代码

代码来源link

class Solution {
    
    
    public int[] findRedundantDirectedConnection(int[][] edges) {
    
    
        //辅助数组parent以及并查集初始化
        int nodesCount = edges.length;//边的数量=结点的数量
        UnionFind uf = new UnionFind(nodesCount + 1);
        int[] parent = new int[nodesCount + 1];//存放每个结点的父亲结点
        for (int i = 1; i <= nodesCount; ++i) {
    
    
            parent[i] = i;//初始化,每个结点的父亲结点是自己
        }
        //冲突/环标签
        int conflict = -1;//冲突:该结点入度为2
        int cycle = -1;//环:成环
		//开始遍历
        //[[1,2], [1,3], [2,3]]
        for (int i = 0; i < nodesCount; ++i) {
    
    
            int[] edge = edges[i];//获取其中一条边<node1,node2>;
            int node1 = edge[0], node2 = edge[1];
            if (parent[node2] != node2) {
    
    
                conflict = i;
            } else {
    
    
                parent[node2] = node1;//改变父亲结点
                if (uf.find(node1) == uf.find(node2)) {
    
    //判断是否成环
                    cycle = i; 
                } else {
    
    
                    uf.union(node1, node2);//合并结点1和结点2
                }
            }
        }
        //获取有问题的边(冲突,环)
        if (conflict < 0) {
    
    //没有冲突,那意味着有成环;
            int[] redundant = {
    
    edges[cycle][0], edges[cycle][1]};
            return redundant;
        } else {
    
    
            int[] conflictEdge = edges[conflict];//冲突边<node1,node2>;
            if (cycle >= 0) {
    
    
                int[] redundant = {
    
    parent[conflictEdge[1]], conflictEdge[1]};
                return redundant;
            } else {
    
    
                int[] redundant = {
    
    conflictEdge[0], conflictEdge[1]};
                return redundant;
            }
        }
    }
}
//并查集:快速获取两者是否存在于同一集合;即判断是否有环
class UnionFind {
    
    //用来存放边
    int[] ancestor;
	//初始化,每个结点指向的边是自己
    public UnionFind(int n) {
    
    
        ancestor = new int[n];
        for (int i = 0; i < n; i++) {
    
    
            ancestor[i] = i;
        }
    }
	//将index1的集合加入到index2的集合中
    public void union(int index1, int index2) {
    
    
        ancestor[find(index1)] = find(index2);
    }
	//用来查找index的祖先
    public int find(int index) {
    
    
        if (ancestor[index] != index) {
    
    
            ancestor[index] = find(ancestor[index]);
        }
        return ancestor[index];
    }
}

猜你喜欢

转载自blog.csdn.net/qq_39457586/article/details/108639822