Skip to content

Latest commit

 

History

History
282 lines (257 loc) · 8.5 KB

1579. Remove Max Number of Edges to Keep Graph Fully Traversable.md

File metadata and controls

282 lines (257 loc) · 8.5 KB

the last one in Weekly Contest 205.

leetcode-cn Daily Challenge on January 27th, 2021.


Difficulty : Hard

Related Topics : Union Find


Alice and Bob have an undirected graph of n nodes and 3 types of edges:

  • Type 1: Can be traversed by Alice only.
  • Type 2: Can be traversed by Bob only.
  • Type 3: Can by traversed by both Alice and Bob.

Given an array edges where edges[i] = [typei, ui, vi] represents a bidirectional edge of type typei between nodes ui and vi, find the maximum number of edges you can remove so that after removing the edges, the graph can still be fully traversed by both Alice and Bob. The graph is fully traversed by Alice and Bob if starting from any node, they can reach all other nodes.

Return the maximum number of edges you can remove, or return -1 if it's impossible for the graph to be fully traversed by Alice and Bob.

Example 1:

1

Input: n = 4, edges = [[3,1,2],[3,2,3],[1,1,3],[1,2,4],[1,1,2],[2,3,4]]
Output: 2
Explanation: If we remove the 2 edges [1,1,2] and [1,1,3]. The graph will still be fully traversable by Alice and Bob. Removing any additional edge will not make it so. So the maximum number of edges we can remove is 2.

Example 2:

2

Input: n = 4, edges = [[3,1,2],[3,2,3],[1,1,4],[2,1,4]]
Output: 0
Explanation: Notice that removing any edge will not make the graph fully traversable by Alice and Bob.

Example 3:

3

Input: n = 4, edges = [[3,2,3],[1,1,2],[2,3,4]]
Output: -1
Explanation: In the current graph, Alice cannot reach node 4 from the other nodes. Likewise, Bob cannot reach 1. Therefore it's impossible to make the graph fully traversable.

Constraints:

  • 1 <= n <= 10^5
  • 1 <= edges.length <= min(10^5, 3 * n * (n-1) / 2)
  • edges[i].length == 3
  • 1 <= edges[i][0] <= 3
  • 1 <= edges[i][1] < edges[i][2] <= n
  • All tuples (typei, ui, vi) are distinct.

Solution

  • mine
    • Java
      • got from the discuss, and the class UnionFind is template code Runtime: 35 ms, faster than 40.33%, Memory Usage: 101.7 MB, less than 35.97% of Java online submissions

        // O(L * log(L)) time
        // O(N)space
        // L = edges.length
        public int maxNumEdgesToRemove(int n, int[][] edges) {
            UnionFind Alice = new UnionFind(n);
            UnionFind Bob = new UnionFind(n);
            int count = 0;
            Arrays.sort(edges, (e1, e2) -> e2[0] - e1[0]);
            for(int[] edge : edges){
                switch(edge[0]){
                    case 1:
                        if(Alice.union(edge[1] - 1, edge[2] - 1)){
                            count++;
                        }
                        break;
                    case 2:
                        if(Bob.union(edge[1] - 1, edge[2] - 1)){
                            count++;
                        }
                        break;
                    case 3:
                        boolean a = Alice.union(edge[1] - 1, edge[2] - 1);
                        boolean b = Bob.union(edge[1] - 1, edge[2] - 1);
                        if (a || b) {
                            count++;
                        }
                        break;
                }
            }
            if(Alice.united() && Bob.united()){
                return edges.length - count;
            }
            return -1;
        }
        
        class UnionFind{
            int size;
            int[] arr;
        
            public UnionFind(int n){
                size = n;
                arr = new int[n];
                for(int i = 0; i < n; i++){
                    arr[i] = i;
                }
            }
        
            boolean united(){
                return size == 1;
            }
        
            boolean union(int a, int b){
                if(find(a) != find(b)){
                    arr[find(a)] = find(b);
                    size--;
                    return true; 
                }
                return false;
            }
        
            int find(int a){
                if(a != arr[a]){
                    arr[a] = find(arr[a]);
                }
                return arr[a];
            }
        }
        
      • Runtime: 34 ms, faster than 22.50%, Memory Usage: 100.6 MB, less than 54.17% of Java online submissions

        public int maxNumEdgesToRemove(int n, int[][] edges) {
            Arrays.sort(edges, (a, b) -> b[0] - a[0]);
            UF A = new UF(n);
            UF B = new UF(n);
            int res = 0;
            for(int[] edge : edges){
                if(edge[0] == 3){
                    //alice and bob
                    boolean a = A.union(edge[1] - 1, edge[2] - 1);
                    boolean b = B.union(edge[1] - 1, edge[2] - 1); 
                    if(!a && !b){
                        res++;
                    }
                }else if(edge[0] == 2){
                    //bob
                    if(!B.union(edge[1] - 1, edge[2] - 1)){
                        res++;
                    }
                }else{
                    //alice
                    if(!A.union(edge[1] - 1, edge[2] - 1)){
                        res++;
                    }
                }
            }
            return B.united() && A.united() ? res : -1;
        }
        
        class UF{
            int count;
            int[] arr;
            public UF(int n){
                count = n;
                arr = new int[n];
                for(int i = 0; i < n; i++){
                    arr[i] = i;
                }
            }
        
            int find(int a){
                if(a != arr[a]){
                    arr[a] = find(arr[a]);
                }
                return arr[a];
            }
        
            boolean union(int a, int b){
                if(find(a) != find(b)){
                    arr[find(a)] = find(b);
                    count--;
                    return true;
                }
                return false;
            }
        
            boolean united(){
                return count == 1;
            }
        }
        

  • the most votes
  • Runtime: 34 ms, faster than 44.57%, Memory Usage: 100.4 MB, less than 38.74% of Java online submissions
    public int maxNumEdgesToRemove(int n, int[][] edges) {
        Arrays.sort(edges, (a, b) -> b[0] - a[0]);
    
        int edgeAdd = 0;
    
        UnionFind alice = new UnionFind(n);
        UnionFind bob = new UnionFind(n);
    
        for (int[] edge : edges) {
            int type = edge[0];
            int a = edge[1];
            int b = edge[2];
    
            switch (type) {
                case 3:
                    if (alice.unite(a, b) | bob.unite(a, b)) {
                        edgeAdd++;
                    }
                    break;
                case 2:
                    if (bob.unite(a, b)) {
                        edgeAdd++;
                    }
                    break;
                case 1:
                    if (alice.unite(a, b)) {
                        edgeAdd++;
                    }
                    break;
            }
        }
    
        return (alice.united() && bob.united()) ? edges.length - edgeAdd : -1;
    }
    
    private class UnionFind {
        int[] component;
        int distinctComponents;
    
        public UnionFind(int n) {
            component = new int[n+1];
            for (int i = 0; i <= n; i++) {
                component[i] = i;
            }
            distinctComponents = n;
        }
        // unite. For example, if previously we have component {0, 4, 4, 4, 4, 6, 7, 7}, then invoke this method with a=1, b=5, then after invoke, {0, 4, 4, 4, 5, 7, 7, 7}
        private boolean unite(int a, int b) {
            if (findComponent(a) != findComponent(b)) {
                component[findComponent(a)] = b;
                distinctComponents--;
                return true;
            }
    
            return false;
        }
    
        // find and change component
        // for example, if previously we have component:{0, 2, 3, 4, 4, 6, 7, 7}, then after invoke this method with a=1, the component become {0, 4, 4, 4, 4, 6, 7, 7}
        private int findComponent(int a) {
            if (component[a] != a) {
                component[a] = findComponent(component[a]);
            }
            return component[a];
        }
    
        private boolean united() {
            return distinctComponents == 1;
        }
    
    }