684. Redundant Connection

这道题给的是无向图。
一个无向图如果是一个树,那它必须是全连通而且不能有环。
这题有几种做法,比较简单的做法是Union Find, 而且复杂度最好。
另外一种写法是答案里给的DFS,复杂度就是N^ 2了
另外一种写法是先找到环,再找到这个环里最后一个出现的边。这个时间复杂度是 O(N)

先写Union Find的写法。
我的错误是手太熟了,所以写union find的时候写错了,union的时候应该把root1 和root2 hookup,
我手太熟没想写成id1, id2了。
总结一下Union Find易错点。 1。Union的时候容易忘了判断两个root是否相等 2。root和id要分清楚。

class Solution {
    public int[] findRedundantConnection(int[][] edges) {
        int N = edges.length;
        UnionFind uf = new UnionFind(N);
        for (int[] edge : edges) {
            int a = edge[0] - 1, b = edge[1] - 1;
            if (!uf.union(a, b)) return edge;
        }
        return null;
    }
}
class UnionFind {
    int[] ids;
    int[] weights;
    public UnionFind(int N) {
        ids = new int[N];
        weights = new int[N];
        for (int i = 0; i < N; i++) {
            ids[i] = i;
            weights[i] = 1;
        }
    }
    public int root(int id) {
        if (ids[id] != id) {
            ids[id] = root(ids[id]);
        }
        return ids[id];
    }
    public boolean union(int id1, int id2) {
        int root1 = root(id1), root2 = root(id2);
        if (root1 == root2) return false;
        if (weights[root1] <= weights[root2]) {
            ids[root1] = root2; //这里是对root的操作,foget about id2, id1
            weights[root2] += weights[root1];
        } else {
            ids[root2] = root1;
            weights[root1] += weights[root2];
        }
        return true;
    }
}

再写第一种DFS的写法。
在进行DFS的时候要注意一点,
由于我们提前进行了预防(不加redundant connection) 所以DFS的时候图一定是没有环的。
因为图是没有环的,所以访问的时候就不需要避免loop了。所以只用一个visited就可以。

class Solution {
    public int[] findRedundantConnection(int[][] edges) {
        int N = edges.length;
        ArrayList[] graph = new ArrayList[N];
        Set visited = new HashSet<>();
        for (int i = 0; i < N; i++) graph[i] = new ArrayList<>();
        for (int[] edge : edges) {
            int a = edge[0] - 1, b = edge[1] - 1;
            visited.clear();
            if (dfs(graph, a, b, visited)) return edge;
            graph[a].add(b);
            graph[b].add(a);
        }
        return null;
    }
    private boolean dfs(ArrayList[] graph, int source, int target, Set visited) {
        // no loop here. We find the loop before the loop appeared.
        if (visited.contains(source)) return false;
        visited.add(source);
        if (source == target) return true;
        for (int child : graph[source]) {
            if (dfs(graph, child, target, visited)) return true;
        }
        return false;
    }
}

再看另一种DFS的解法。
就是先把环找出来,再遍历整个环, 看谁是最后一个出现的点。
这种做法还是ON的时间复杂度。就是用了LinkedHashSet这种数据结构来进行O1查询和保存它出现的顺序。

class Solution {
    public int[] findRedundantConnection(int[][] edges) {
        int N = edges.length;
        ArrayList[] graph = new ArrayList[N];
        LinkedHashSet visiting = new LinkedHashSet<>();
        for (int i = 0; i < N; i++) graph[i] = new ArrayList<>();
        Map edgeId = new HashMap<>();
        for (int i = 0; i < edges.length; i++) {
            int[] edge = edges[i];
            int a = edge[0] - 1, b = edge[1] - 1;
            graph[a].add(b);
            graph[b].add(a);
            edgeId.put(a * N + b, i);
            edgeId.put(b * N + a, i);
        }
        
        List loop = getLoop(graph, visiting);
        int lastId = -1;
        for (int i = 0; i < loop.size(); i++) {
            int a = loop.get(i), b = (i == loop.size() - 1) ? loop.get(0) : loop.get(i + 1);
            if (edgeId.get(a * N + b) > lastId) lastId = edgeId.get(a * N + b);
        }
        
        return edges[lastId];
    }
    private List getLoop(ArrayList[] graph, LinkedHashSet visiting) {
        Integer start = dfs(graph, visiting, 0, -1);
        List loop = new ArrayList<>();
        Iterator it = visiting.iterator();
        boolean started = false;
        while (it.hasNext()) {
            int a = it.next();
            if (a == start) {
                started = true;
            }
            if (started) loop.add(a);
        }
        return loop;
    }
    
    private Integer dfs(ArrayList[] graph, LinkedHashSet visiting, int source, int parent) {
        if (visiting.contains(source)) return source;
        visiting.add(source);
        for (int next : graph[source]) {
            if (next != parent) {
                Integer ans = dfs(graph, visiting, next, source);
                if (ans != null) return ans; // find a loop, return the loop starting position
            }
        }
        visiting.remove(source);
        return null;
    }
}

你可能感兴趣的:(684. Redundant Connection)