Leetcode 261. Graph Valid Tree
题目
Given n
nodes labeled from 0
to n - 1
and a list of undirected edges (each edge is a pair of nodes), write a function to check whether these edges make up a valid tree.
Example 1:
Example 2:
Note: You can assume that no duplicate edges will appear in edges
. Since all edges are undirected, [0,1]
is the same as [1,0]
and thus will not appear together in edges
.
思路
这是一道经典的图表题。要判断一个Graph是不是Tree,我们需要知道树的两个充分必要条件: 1. 有且仅有一个connected component. 2. 图形中没有环.
要满足这两个条件,首先,这个图形edges
的数量必须恰好等于node
的数量减一。在这道题目中,即: edges.length = n - 1
。当edges
数量小于n - 1
时,必然有节点没有与其他节点相连,违反了 树的第一条性质;当edge
数量大于n - 1
的时候,我们可以用鸽子洞理论证明,图形中必然有环,违反了 树的第二条性质。
其次,edges
数量恰好等于n-1
并不表示图像中一定没有环。我们需要用其他的方法来检查图形中是否有 环。我们可以采用union-find
的思想。我们创建一个新的数组unions
,对于每条edge (u, v)
, 我们令unions[v] = u
。这样我们记录了u
的parent
为v
。这样,在遇见新的edge (x, y)
时, 我们利用unions
来追溯x
和y
最深的祖先,如果他们有同一个祖先,则edge (x, y)
必定造成环。
当edges.length == n - 1
并且检查所有edges
都不构成环的时候,我们就可以说这个图形一定为树。
解答
在这个解法中,我们注意到在unions
数组中,我们并未对每个unions[v]
保存其直接的parent u
, 而是保存了v
通过find
找到的最深的祖先。直观上理解,我们可以认为u
与v
原本存在于不同的集合, 各自集合的代表为其最深的祖先。当我们遇见edge (u, v)
,我们则将两个集合合并在了一起,让u
的祖先 为这个新集合的代表。
Complexity Analysis
Time Complexity: O(E * V). 我们循环遍历了所有的边,并且对于每条边,我们需要通过
find
寻找边两个端点的最深祖先(最坏情况下会找V次),因此时间复杂度为O(EV).
Space Complexity: O(V). 我们创建了新的数组来储存所有节点的祖先。
拓展
我们可以使用BFS和DFS解决这道题吗?这两种解法的时间空间复杂度又是多少呢?
更多关于
union-find
以及disjoint set
的图解及示例请参见这里
总结
解决这类问题我们需要非常清楚各类图形的概念,深入掌握他们的特征。 同时,我们还需要对union-find
这类方法非常熟悉,能够手到擒来。
Last updated
Was this helpful?