684. Redundant Connection
684. Redundant Connection https://www.youtube.com/watch?v=4hJ721ce010 Sol 1 : union find Time is n With no path compression and union by size class Solution { public int[] findRedundantConnection(int[][] edges) { int n = edges.length; UnionFind uf = new UnionFind(n); for(int[] edge : edges){ int u = edge[0]; int v = edge[1]; if(uf.find(u) == uf.find(v)){ return edge; }else{ uf.union(u, v); } } return null; } class UnionFind{ int[] parent; public UnionFind(int n){ parent = new int[n + 1]; for(int i = 1; i < n + 1; i++){ parent[i] = i; } } public void union(int a, int b){ int pa = find(a); int pb = find(b); parent[pa] = pb; } public int find(int x){ while(parent[x] != x){ x = parent[x]; } return x; } } } Sol 2 : dfs time n^2 class Solution { public int[] findRedundantConnection(int[][] edges) { List<List<Integer>> adjList = new ArrayList<>(); for(int i = 0; i < edges.length + 1; i++){ adjList.add(new ArrayList<>()); } for(int[] edge : edges){ int v = edge[0]; int u = edge[1]; HashSet<Integer> visited = new HashSet<>(); if(dfs(visited, u, v, adjList)){ // return true if there's a path between u and v already // connect u and v directly make it a graph from tree return edge; } // if the path doesnt exist adjList.get(u).add(v); adjList.get(v).add(u); } return null; } private boolean dfs(HashSet<Integer> visited, int u, int v, List<List<Integer>> adjList){ // base case , when u and v are the same pos if(u == v) return true; // else, mark u as visited visited.add(u); // check if u and v are in the adjList, if no, there is def no path // is it necessary ? esp using list is not like hashmap. its not O(1) look up // check every nei, dfs on nei for(int nei : adjList.get(u)){ if(visited.contains(nei)) continue; if(dfs(visited, nei, v, adjList)) return true; } return false; } }
// uf with path compression and union by rank Logical Thought And edge will connect two nodes into one connected component. When we count an edge in, if the two nodes have already been in the same connected component, the edge will result in a cycle, so it is redundant. We can make use of Disjoint Sets (Union Find): Initially, each node can be regarded as a disjoint set. When we count an edge in, we UNION two nodes, If two nodes have already been in the same disjoint set (we detect that with the help of FIND), the current edge is redundant. For example, 1 / \ 2 - 3 Initially, there are 3 disjoint sets: 1, 2, 3. Edge [1,2] connects 1 to 2, i.e., 1 and 2 are grouped together. Edge [1,3] connects 1 to 3, i.e., 1 and 3 are grouped together. Edge [2,3] connects 2 to 3, but 2 and 3 have been in the same disjoint set already, so [2, 3] is redundant. Clear Java code public int[] findRedundantConnection(int[][] edges) { DisjointSets disjointSets = new DisjointSets(edges.length + 1); int u, v; for (int[] edge : edges) { u = edge[0]; v = edge[1]; if (!disjointSets.union(u, v)) { return edge; } } return new int[2]; } static class DisjointSets { private static int[] parent; private static int[] rank; public DisjointSets(int n) { parent = new int[n]; rank = new int[n]; Arrays.fill(rank, 1); } public int find(int x) { if (0 == parent[x]) return x; return parent[x] = find(parent[x]); } public boolean union(int x, int y) { int rootOfX = find(x), rootOfY = find(y); if (rootOfX != 0 && rootOfX == rootOfY) return false; if (rank[rootOfX] < rank[rootOfY]) { parent[rootOfX] = rootOfY; rank[rootOfY] += rank[rootOfX]; } else { parent[rootOfY] = rootOfX; rank[rootOfX] += rank[rootOfY]; } return true; } } Attention:The Union by Rank and Path Compression can optimize the time complexity from O(n) to O(logn) (even smaller).
In this problem, a tree is an undirected graph that is connected and has no cycles.
The given input is a graph that started as a tree with N nodes (with distinct values 1, 2, ..., N), with one additional 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] with u < v, that represents an undirected edge connecting nodes u and v.
Return an edge that can be removed so that the resulting graph is a tree of N nodes. If there are multiple answers, return the answer that occurs last in the given 2D-array. The answer edge [u, v] should be in the same format, with u < v.
Example 1:
Input: [[1,2], [1,3], [2,3]] Output: [2,3] Explanation: The given undirected graph will be like this: 1 / \ 2 - 3
Example 2:
Input: [[1,2], [2,3], [3,4], [1,4], [1,5]]
Output: [1,4]
Explanation: The given undirected graph will be like this:
5 - 1 - 2
| |
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.
Update (2017-09-26):
We have overhauled the problem description + test cases and specified clearly the graph is an undirectedgraph. For the directed graph follow up please see Redundant Connection II). We apologize for any inconvenience caused.
posted on 2018-08-28 20:08 猪猪🐷 阅读(173) 评论(0) 收藏 举报
浙公网安备 33010602011771号