leetcode | 684. Redundant Connection

题目

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.

思路与解法

方法一

从题目中可知,我们需要从一个图中找出一条多余的边,使得去掉该边之后,剩余的节点和边形成一棵树(连通且无环)。题目保证输入数据有解,则我们可知输入数据为连通图,且一定至少存在一条边满足题目要求(该边与某些边形成了环)。
对于此题,我们仍然可以使用“剥洋葱”的思想:首先将度数为1的节点去掉,将与其相连节点的度数减1;之后,将当前图中度数为1的节点去掉,再将与其相连节点的度数减1……不断去掉度数为1的节点,直到没有度数为1的节点。此时,剩下的节点与边一定形成了环。最后,遍历该环上的每条边,找到最后输入的那条边返回即可。

代码实现

此算法我才用go语言实现:

func findRedundantConnection(edges [][]int) []int {
    /*
    * graph		存储图
    * nodes_num	存储节点数,可有len(edges)计算得到
    * degree	存储节点的度数
    * visited	存储节点是否被删除,true表示已删除
    * queue		利用队列实现BFS
    */
    graph := make(map[int][]int)
    nodes_num := len(edges)
    degree := make([]int, nodes_num+1)
    visited := make([]bool, nodes_num+1)
    queue := make([]int ,0)
    /* 存储graph,统计各节点度数 */
    for _, edge :=range edges {
        graph[edge[0]] = append(graph[edge[0]], edge[1])
        graph[edge[1]] = append(graph[edge[1]], edge[0])
        degree[edge[0]]++
        degree[edge[1]]++
    }
    /* 将度数为1的节点加入到队列中,等待删除 */
    for i:=1; i<=nodes_num; i++ {
        if degree[i] == 1 {
            queue = append(queue, i)
        }
    }
    /* 直到寻找不到度数为1的节点,退出循环 */
    for len(queue) > 0 {
        head := queue[0]
        queue = queue[1:]
        visited[head] = true
        for _, edge := range graph[head] {
            degree[edge]--
            if degree[edge] == 1 {
                queue = append(queue, edge)
            }
        }
    }
    /* 从后向前遍历edges,返回满足visited[edges[i][0]] == false && visited[edges[i][1]] == false的边*/
    for i:=nodes_num-1; i>=0 ;i-- {
        if visited[edges[i][0]] == false && visited[edges[i][1]] == false {
            return edges[i]
        }
    }
    return nil
}

评测结果

在这里插入图片描述

方法二

我们可以采用并查集的思想:假如节点uv之间存在一条边,则可以设置parent[u]=v,即u的父亲节点是v,如果yu也相连,则可以设置parent[y]=u,即y的父亲节点是u;此时可以递归查询得到u的父亲是vy并没有父亲节点,其父亲即为自己),所以,可以设置parent[y]=v,即将yv直接相连。经过这样的处理,可以得知,一个连通分量的所有节点最终只存在一个父亲节点(此节点的父亲节点即为自身)。可以思考这样的情况:如果两个节点mn经过边edge相连,查找mn的父亲节点相同,则表明mn已经存在于同一个连通分量(mn存在一条路径),则edge即为查询的边。

扫描二维码关注公众号,回复: 3691326 查看本文章

代码实现

func findRedundantConnection(edges [][]int) []int {
    /* parents存储各个节点的父亲节点 */
    parents := make([]int ,len(edges)+1)
    /* 查找一条边两个节点的父亲节点,并判断是否相等 */
    for _, edge := range edges {
        parent0 := findParent(edge[0], parents)
        parent1 := findParent(edge[1], parents)

        if parent0 == parent1 {
            return edge
        }

        parents[parent0] = parent1
    }
    return []int{}
}
/* 递归查询node的父亲节点,如果不存在,则其父亲节点为自身 */
func findParent(node int, parents []int) int {
    if parents[node] == 0 {
        return node
    }
    return findParent(parents[node], parents)
}

评测结果

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/liuyh73/article/details/83058433