LeetCode 685. Redundant Connection II 冗余连接 II (C++/Java)
题目:
In this problem, a rooted tree is a directed graph such that, there is exactly one node (the root) for which all other nodes are descendants of this node, plus every node has exactly one parent, except for the root node which has no parents.
The given input is a directed graph that started as a rooted tree with N nodes (with distinct values 1, 2, ..., N), with one additional directed edge added. The added edge has two different vertices chosen from 1 to N, and was not an edge that already existed.
The resulting graph is given as a 2D-array of edges
. Each element of edges
is a pair [u, v]
that represents a directed edge connecting nodes u
and v
, where u
is a parent of child v
.
Return an edge that can be removed so that the resulting graph is a rooted tree of N nodes. If there are multiple answers, return the answer that occurs last in the given 2D-array.
Example 1:
Input: [[1,2], [1,3], [2,3]] Output: [2,3] Explanation: The given directed graph will be like this: 1 / \ v v 2-->3
Example 2:
Input: [[1,2], [2,3], [3,4], [4,1], [1,5]] Output: [4,1] Explanation: The given directed graph will be like this: 5 <- 1 -> 2 ^ | | v 4 <- 3
Note:
- The size of the input 2D-array will be between 3 and 1000.
- Every integer represented in the 2D-array will be between 1 and N, where N is the size of the input array.
分析:
这道题是LeetCode 684. Redundant Connection 冗余连接(C++/Java)的进阶版,还是利用并查集的思路做,不会的同学可以先看一下前面的题解。
685题将图更改为有向图,最后要求删去一条边得到一颗树,也就是要求只能有一个根节点,每一个节点只有一个父节点。
那么如果在图中有一个节点有两个父结点时,则要删去的边就必定是这两条边中构成环的一条,如果所有的节点都只有一个父结点,那么删去的边就是构成环的那一条边,基于这个思路,先遍历所有的边,存储他们的父亲节点,当发现有节点的父节点已存在时,将原来的父结点和这个节点记做结果1,新的父节点和这个节点记做结果2,在这里我们将后出现的边做一个标记。因为在做并查集时,发现有环的话,无法立刻判断出这两条边到底那条在环中,所以我们将新来的边做标记,在构建并查集时,不将新的边加入,那么如果最后图内无环则直接返回结果2,如果有环且结果1不为空就返回结果1,如果结果1为空则表明不存在多个父结点的节点,那么就和684题一样了,直接返回构成环的边即可。
程序:
C++
class Solution { public: vector<int> findRedundantDirectedConnection(vector<vector<int>>& edges) { int n = edges.size(); vector<int> parents(n+1, 0); vector<int> root(n+1, 0); vector<int> res1; vector<int> res2; for(auto &edge:edges){ int u = edge[0]; int v = edge[1]; if(parents[v] > 0){ res1 = {parents[v], v}; res2 = edge; edge[0] = -1; edge[1] = -1; } parents[v] = u; } for(auto edge:edges){ int u = edge[0]; int v = edge[1]; if(u < 0 || v < 0) continue; if(!root[u]) root[u] = u; if(!root[v]) root[v] = v; int pu = find(u, root); int pv = find(v, root); //有环 if(pu == pv){ return res1.empty() ? edge : res1; } root[pv] = pu; } return res2; } private: int find(int node, vector<int>& root){ while(root[node] != node){ root[node] = root[root[node]]; node = root[node]; } return node; } };
Java
class Solution { public int[] findRedundantDirectedConnection(int[][] edges) { int n = edges.length; int[] parents = new int[n+1]; int[] roots = new int[n+1]; int[] res1 = null; int[] res2 = null; for(int[] edge:edges){ int u = edge[0]; int v = edge[1]; if(parents[v] > 0){ res1 = new int[]{parents[v], v}; res2 = new int[]{u, v}; edge[0] = -1; edge[1] = -1; } parents[v] = u; } for(int[] edge:edges){ int u = edge[0]; int v = edge[1]; if(u < 0 || v < 0) continue; if(roots[u] == 0) roots[u] = u; if(roots[v] == 0) roots[v] = v; int pu = find(u, roots); int pv = find(v, roots); if(pu == pv){ return res1 == null ? edge : res1; } roots[pv] = pu; } return res2; } private int find(int node, int[] roots){ while(node != roots[node]){ roots[node] = roots[roots[node]]; node = roots[node]; } return node; } }