DFS
https://www.geeksforgeeks.org/check-given-graph-tree/
判断一个Graph是否为Tree有两个条件:1) 连通图 2) 没有环
这道题是无向图,判断有没有环可以dfs来做,比有向图容易很多。
dfs判断图是否有环:Detect Cycle In Directed/Undirected Graph
判断是否是连通图很容易,在dfs一个node后,只要看看是不是所有节点都visit过了即可。
也可以用图论的知识,对于Tree,|E| = |V|-1
时间复杂度 O(V+E)
class Solution { public: vectorint>> adj; bool validTree(int n, vector
int>>& edges) { adj.resize(n,list<int>()); for (auto edge:edges){ int u=edge[0], v=edge[1]; adj[u].push_back(v); adj[v].push_back(u); } vector<bool> visited(n,false); if (dfs(0,visited,-1)) return false; for (bool x:visited){ if (x==false) return false; } return true; } bool dfs(int i, vector<bool> &visited, int parent){ // return if has cycle visited[i] = true; for (auto x:adj[i]){ if (visited[x] && x!=parent) return true; if (!visited[x]){ if (dfs(x,visited,i)) return true; } } return false; } };
Union Find
https://www.geeksforgeeks.org/union-find-algorithm-set-2-union-by-rank/
用uniond find来做也是可以的,而且更加直观。由于节点0~n-1,可以用一个parent数组来做。
数组来做的话用size来判断如何union比较简单,用parent[root]=-size即可。
时间复杂度比较复杂,如果没有path compression,union和find都需要logV,所以总的复杂度为ElogV。
加上path compression后,union和find 都是 amortized O(1)。
class Solution { public: vector<int> parent; bool validTree(int n, vectorint>>& edges) { if (edges.size()!=n-1) return false; parent.resize(n,-1); for (auto edge:edges){ int u=edge[0], v=edge[1]; int root1=Find(u), root2=Find(v); if (root1==root2) return false; // whoever's size is bigger becomes parent of other // notice parent[root] is negative, if parent[root] is smaller, then its size is larger if (root1>root2){ parent[root2] += parent[root1]; parent[root1] = root2; }else{ parent[root1] += parent[root2]; parent[root2] = root1; } } return true; } int Find(int x){ if (parent[x]<0) return x; return parent[x]=Find(parent[x]); } };