5a3c1b2d创建于 2025年8月3日历史提交
/**
 * https://leetcode.com/problems/graph-valid-tree/
 * Time O(E * a(N)) | Space O(V)
 * @param {number} n
 * @param {number[][]} edges
 * @return {boolean}
 */
var validTree = function (n, edges, root = 0) {
    const isEqual = edges.length === n - 1;
    if (!isEqual) return false;

    const { graph, visited } = buildGraph(n, edges);

    dfs(root, graph, visited);

    return visited.size === n;
};

var initGraph = (n) => ({
    graph: new Array(n).fill().map(() => []),
    visited: new Set(),
});

var buildGraph = (n, edges) => {
    const { graph, visited } = initGraph(n);

    for (const [src, dst] of edges) {
        graph[src].push(dst);
        graph[dst].push(src);
    }

    return { graph, visited };
};

const dfs = (node, graph, visited) => {
    if (visited.has(node)) return;
    visited.add(node);

    for (const neighbor of graph[node]) {
        dfs(neighbor, graph, visited);
    }
};

/**
 * https://leetcode.com/problems/graph-valid-tree/
 * Time O(E * a(N)) | Space O(V)
 * @param {number} n
 * @param {number[][]} edges
 * @return {boolean}
 */
var validTree = function (n, edges) {
    const isEqual = edges.length === n - 1;
    if (!isEqual) return false;

    const { graph, visited, queue } = buildGraph(n, edges);

    bfs(graph, visited, queue);

    return visited.size === n;
};

var initGraph = (n) => ({
    graph: new Array(n).fill().map(() => []),
    visited: new Set(),
    queue: new Queue(),
    root: 0,
});

var buildGraph = (n, edges) => {
    const { graph, visited, queue, root } = initGraph(n);

    for (const [src, dst] of edges) {
        graph[src].push(dst);
        graph[dst].push(src);
    }

    queue.enqueue(root);
    visited.add(root);

    return { graph, visited, queue };
};

const bfs = (graph, visited, queue) => {
    while (!queue.isEmpty()) {
        for (let i = queue.size() - 1; 0 <= i; i--) {
            checkNeighbor(graph, visited, queue);
        }
    }
};

const checkNeighbor = (graph, visited, queue) => {
    const node = queue.dequeue();

    for (const neighbor of graph[node]) {
        if (visited.has(neighbor)) continue;
        visited.add(neighbor);

        queue.enqueue(neighbor);
    }
};

/**
 * https://leetcode.com/problems/graph-valid-tree/
 * Time O(E * a(N)) | Space O(V)
 * @param {number} n
 * @param {number[][]} edges
 * @return {boolean}
 */
var validTree = function (n, edges) {
    const union = new Array(n).fill(-1);

    for (const [src, dst] of edges) {
        const [x, y] = [find(union, src), find(union, dst)];

        const hasCycle = x === y;
        if (hasCycle) return false;

        compress(union, x, y);
    }

    const isValid = edges.length === n - 1;
    return isValid;
};

const compress = (union, i, head) => (union[i] = head);

const find = (union, i, num = union[i]) => {
    const isEmpty = num === -1;
    if (isEmpty) return i;

    const head = find(union, num);

    compress(union, i, head);

    return union[i];
};