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  猪猪&#128055;  阅读(173)  评论(0)    收藏  举报

导航