Welcome to Subscribe On Youtube

261. Graph Valid Tree

Description

You have a graph of n nodes labeled from 0 to n - 1. You are given an integer n and a list of edges where edges[i] = [ai, bi] indicates that there is an undirected edge between nodes ai and bi in the graph.

Return true if the edges of the given graph make up a valid tree, and false otherwise.

 

Example 1:

Input: n = 5, edges = [[0,1],[0,2],[0,3],[1,4]]
Output: true

Example 2:

Input: n = 5, edges = [[0,1],[1,2],[2,3],[1,3],[1,4]]
Output: false

 

Constraints:

  • 1 <= n <= 2000
  • 0 <= edges.length <= 5000
  • edges[i].length == 2
  • 0 <= ai, bi < n
  • ai != bi
  • There are no self-loops or repeated edges.

Solutions

Solution 1

Union find.

Solution 2: DFS

We can also use depth-first search to determine whether there is a cycle. We can use an array $vis$ to record the visited nodes. During the search, we first mark the node as visited, then traverse the nodes adjacent to this node. If the adjacent node has been visited, we skip it, otherwise we recursively visit the adjacent node. Finally, we check whether all nodes have been visited. If there are nodes that have not been visited, it means that it cannot form a tree, so we return false.

The time complexity is $O(n)$, and the space complexity is $O(n)$, where $n$ is the number of nodes.

  • class Solution {
        private int[] p;
    
        public boolean validTree(int n, int[][] edges) {
            p = new int[n];
            for (int i = 0; i < n; ++i) {
                p[i] = i;
            }
            for (int[] e : edges) {
                int a = e[0], b = e[1];
                if (find(a) == find(b)) {
                    return false;
                }
                p[find(a)] = find(b);
                --n;
            }
            return n == 1;
        }
    
        private int find(int x) {
            if (p[x] != x) {
                p[x] = find(p[x]);
            }
            return p[x];
        }
    }
    
    
    // Solution 2
    class Solution {
        private List<Integer>[] g;
        private Set<Integer> vis = new HashSet<>();
    
        public boolean validTree(int n, int[][] edges) {
            if (edges.length != n - 1) {
                return false;
            }
            g = new List[n];
            Arrays.setAll(g, k -> new ArrayList<>());
            for (var e : edges) {
                int a = e[0], b = e[1];
                g[a].add(b);
                g[b].add(a);
            }
            dfs(0);
            return vis.size() == n;
        }
    
        private void dfs(int i) {
            vis.add(i);
            for (int j : g[i]) {
                if (!vis.contains(j)) {
                    dfs(j);
                }
            }
        }
    }
    
    
  • class Solution {
    public:
        vector<int> p;
    
        bool validTree(int n, vector<vector<int>>& edges) {
            p.resize(n);
            for (int i = 0; i < n; ++i) p[i] = i;
            for (auto& e : edges) {
                int a = e[0], b = e[1];
                if (find(a) == find(b)) return 0;
                p[find(a)] = find(b);
                --n;
            }
            return n == 1;
        }
    
        int find(int x) {
            if (p[x] != x) p[x] = find(p[x]);
            return p[x];
        }
    };
    
    
    // Solution 2
    class Solution {
    public:
        bool validTree(int n, vector<vector<int>>& edges) {
            if (edges.size() != n - 1) {
                return false;
            }
            vector<int> g[n];
            vector<int> vis(n);
            function<void(int)> dfs = [&](int i) {
                vis[i] = true;
                --n;
                for (int j : g[i]) {
                    if (!vis[j]) {
                        dfs(j);
                    }
                }
            };
            for (auto& e : edges) {
                int a = e[0], b = e[1];
                g[a].push_back(b);
                g[b].push_back(a);
            }
            dfs(0);
            return n == 0;
        }
    };
    
    
  • class Solution:
        def validTree(self, n: int, edges: List[List[int]]) -> bool:
            def find(x):
                if p[x] != x:
                    p[x] = find(p[x])
                return p[x]
    
            p = list(range(n))
            for a, b in edges:
                if find(a) == find(b):
                    return False
                p[find(a)] = find(b)
                n -= 1
            return n == 1
    
    
    # Solution 2
    class Solution:
        def validTree(self, n: int, edges: List[List[int]]) -> bool:
            def dfs(i: int):
                vis.add(i)
                for j in g[i]:
                    if j not in vis:
                        dfs(j)
    
            if len(edges) != n - 1:
                return False
            g = [[] for _ in range(n)]
            for a, b in edges:
                g[a].append(b)
                g[b].append(a)
            vis = set()
            dfs(0)
            return len(vis) == n
    
    
  • func validTree(n int, edges [][]int) bool {
    	p := make([]int, n)
    	for i := range p {
    		p[i] = i
    	}
    	var find func(x int) int
    	find = func(x int) int {
    		if p[x] != x {
    			p[x] = find(p[x])
    		}
    		return p[x]
    	}
    	for _, e := range edges {
    		a, b := e[0], e[1]
    		if find(a) == find(b) {
    			return false
    		}
    		p[find(a)] = find(b)
    		n--
    	}
    	return n == 1
    }
    
    
    // Solution 2
    func validTree(n int, edges [][]int) bool {
    	if len(edges) != n-1 {
    		return false
    	}
    	g := make([][]int, n)
    	vis := make([]bool, n)
    	for _, e := range edges {
    		a, b := e[0], e[1]
    		g[a] = append(g[a], b)
    		g[b] = append(g[b], a)
    	}
    	var dfs func(int)
    	dfs = func(i int) {
    		vis[i] = true
    		n--
    		for _, j := range g[i] {
    			if !vis[j] {
    				dfs(j)
    			}
    		}
    	}
    	dfs(0)
    	return n == 0
    }
    
    
  • /**
     * @param {number} n
     * @param {number[][]} edges
     * @return {boolean}
     */
    var validTree = function (n, edges) {
        let p = new Array(n);
        for (let i = 0; i < n; ++i) {
            p[i] = i;
        }
        function find(x) {
            if (p[x] != x) {
                p[x] = find(p[x]);
            }
            return p[x];
        }
        for (const [a, b] of edges) {
            if (find(a) == find(b)) {
                return false;
            }
            p[find(a)] = find(b);
            --n;
        }
        return n == 1;
    };
    
    
    // Solution 2
    /**
     * @param {number} n
     * @param {number[][]} edges
     * @return {boolean}
     */
    var validTree = function (n, edges) {
        if (edges.length !== n - 1) {
            return false;
        }
        const g = Array.from({ length: n }, () => []);
        const vis = Array.from({ length: n }, () => false);
        for (const [a, b] of edges) {
            g[a].push(b);
            g[b].push(a);
        }
        const dfs = i => {
            vis[i] = true;
            --n;
            for (const j of g[i]) {
                if (!vis[j]) {
                    dfs(j);
                }
            }
        };
        dfs(0);
        return n === 0;
    };
    
    

All Problems

All Solutions