[LeetCode] Graph Valid Tree 圖驗證樹 LeetCode All in One 題目講解彙總(持續更新中...)

 

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.html

For example:java

Given n = 5 and edges = [[0, 1], [0, 2], [0, 3], [1, 4]], return true.node

Given n = 5 and edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]], return false.數組

Hint:app

  1. Given n = 5 and edges = [[0, 1], [1, 2], [3, 4]], what should your return? Is this case a valid tree?
  2. According to the definition of tree on Wikipedia: 「a tree is an undirected graph in which any two vertices are connected by exactly one path. In other words, any connected graph without simple cycles is a tree.」

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.函數

 

這道題給了咱們一個無向圖,讓咱們來判斷其是否爲一棵樹,咱們知道若是是樹的話,全部的節點必須是鏈接的,也就是說必須是連通圖,並且不能有環,因此咱們的焦點就變成了驗證是不是連通圖和是否含有環。咱們首先用DFS來作,根據pair來創建一個圖的結構,用鄰接鏈表來表示,還須要一個一位數組v來記錄某個節點是否被訪問過,而後咱們用DFS來搜索節點0,遍歷的思想是,當DFS到某個節點,先看當前節點是否被訪問過,若是已經被訪問過,說明環存在,直接返回false,若是未被訪問過,咱們如今將其狀態標記爲已訪問過,而後咱們到鄰接鏈表裏去找跟其相鄰的節點繼續遞歸遍歷,注意咱們還須要一個變量pre來記錄上一個節點,以避免回到上一個節點,這樣遍歷結束後,咱們就把和節點0相鄰的節點都標記爲true,而後咱們在看v裏面是否還有沒被訪問過的節點,若是有,則說明圖不是徹底連通的,返回false,反之返回true,參見代碼以下:post

 

解法一:this

// DFS
class Solution {
public:
    bool validTree(int n, vector<pair<int, int>>& edges) {
        vector<vector<int>> g(n, vector<int>());
        vector<bool> v(n, false);
        for (auto a : edges) {
            g[a.first].push_back(a.second);
            g[a.second].push_back(a.first);
        }
        if (!dfs(g, v, 0, -1)) return false;
        for (auto a : v) {
            if (!a) return false;
        }
        return true;
    }
    bool dfs(vector<vector<int>> &g, vector<bool> &v, int cur, int pre) {
        if (v[cur]) return false;
        v[cur] = true;
        for (auto a : g[cur]) {
            if (a != pre) {
                if (!dfs(g, v, a, cur)) return false;
            }
        }
        return true;
    }
};

 

下面咱們來看BFS的解法,思路很相近,須要用queue來輔助遍歷,這裏咱們沒有用一維向量來標記節點是否訪問過,而是用了一個set,若是遍歷到一個節點,在set中沒有,則加入set,若是已經存在,則返回false,還有就是在遍歷鄰接鏈表的時候,遍歷完成後須要將節點刪掉,參見代碼以下:url

 

解法二:spa

// BFS
class Solution {
public:
    bool validTree(int n, vector<pair<int, int>>& edges) {
        vector<unordered_set<int>> g(n, unordered_set<int>());
        unordered_set<int> s{{0}};
        queue<int> q{{0}};
        for (auto a : edges) {
            g[a.first].insert(a.second);
            g[a.second].insert(a.first);
        }
        while (!q.empty()) {
            int t = q.front(); q.pop();
            for (auto a : g[t]) {
                if (s.count(a)) return false;
                s.insert(a);
                q.push(a);
                g[a].erase(t);
            }
        }
        return s.size() == n;
    }
};

 

咱們再來看Union Find的方法,這種方法對於解決連通圖的問題頗有效,思想是咱們遍歷節點,若是兩個節點相連,咱們將其roots值連上,這樣能夠幫助咱們找到環,咱們初始化roots數組爲-1,而後對於一個pair的兩個節點分別調用find函數,獲得的值若是相同的話,則說明環存在,返回false,不一樣的話,咱們將其roots值union上,參見代碼以下:

 

解法三:

// Union Find
class Solution {
public:
    bool validTree(int n, vector<pair<int, int>>& edges) {
        vector<int> roots(n, -1);
        for (auto a : edges) {
            int x = find(roots, a.first), y = find(roots, a.second);
            if (x == y) return false;
            roots[x] = y;
        }
        return edges.size() == n - 1;
    }
    int find(vector<int> &roots, int i) {
        while (roots[i] != -1) i = roots[i];
        return i;
    }
};

 

相似題目:

Number of Islands II

Number of Connected Components in an Undirected Graph

 

參考資料:

https://leetcode.com/discuss/85398/bfs-java-solution

https://leetcode.com/discuss/80142/my-c-union-find-code

https://leetcode.com/discuss/52563/ac-java-union-find-solution

https://leetcode.com/discuss/86035/c-dfs-with-adjacent-list-graph

 

LeetCode All in One 題目講解彙總(持續更新中...)

相關文章
相關標籤/搜索