LeetCode Entry

2192. All Ancestors of a Node in a Directed Acyclic Graph

29.06.2024 medium 2024 kotlin rust

List of ancestors in a DAG

2192. All Ancestors of a Node in a Directed Acyclic Graph medium blog post substack youtube 2024-06-29_08-11_1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/654

Problem TLDR

List of ancestors in a DAG #medium #dfs #toposort

Intuition

2024-06-29_08-14.webp We can use Depth-First Search for each node, caching the result to not execute twice, but we should walk backwards from child to parent.

Another solution is to walk from parents in a Topological Sort order and appending the results.

Approach

Let’s implement both approaches. For the toposort solution (in Rust), we should do deduplication as early as possible to prevent OOM.

Complexity

  • Time complexity: \(O(E^2V + V^2log(V))\) for DFS - groupBy will take O(E), DFS depth is O(E) and inside it we iterate over each sibling O(X), X is up to E where we do copy of all collected vertices O(V). The final step is sorting V collected vertexes - VlogV.

\(O(V + EVlog(V))\), the Kahn algorithm for toposort takes O(V + E), in each step of edge taking we append V vertices, and sorting them Vlog(V)

  • Space complexity: \(O(V^2 + E)\) result takes the biggest space

Code


    fun getAncestors(n: Int, edges: Array<IntArray>): List<List<Int>> {
        val g = edges.groupBy({ it[1] }, { it[0] })
        val res = mutableMapOf<Int, Set<Int>>()
        fun dfs(i: Int): Set<Int> = res.getOrPut(i) {
            g[i]?.map { dfs(it) + it }?.flatten()?.toSet() ?: setOf()
        }
        return (0..<n).map { dfs(it).sorted() }
    }


    pub fn get_ancestors(n: i32, edges: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
        let n = n as usize; let (mut deg, mut g, mut res, mut queue) =
            (vec![0; n], vec![vec![]; n], vec![vec![]; n], VecDeque::new());
        for e in edges {
            g[e[0] as usize].push(e[1] as usize); deg[e[1] as usize] += 1
        }
        for i in 0..n { if deg[i] == 0 { queue.push_back(i); }}
        while let Some(top) = queue.pop_front() { for &j in &g[top] {
            deg[j] -= 1; if deg[j] == 0 { queue.push_back(j); }
            res[j].push(top as i32); let t = res[top].clone();
            res[j].extend(t); res[j].sort_unstable(); res[j].dedup()
        }}; res
    }