LeetCode Entry

3372. Maximize the Number of Target Nodes After Connecting Trees I

28.05.2025 medium 2025 kotlin rust

Max k-reachable nodes of merged trees

3372. Maximize the Number of Target Nodes After Connecting Trees I medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1002

Problem TLDR

Max k-reachable nodes of merged trees #medium #dfs

Intuition

The brute-force DFS is accepted.

Chain-of-thoughts:


    // for k - 1
    // find the most optimal spot on edges2
    // how many nodes can be (k-1) reached from each node
    // solve same problem for edges1(k) and edges2(k-1)
    // 1000 edges, brute-force bfs from each 1000*k, n^2
    // lets write brute-force, no good ideas (23 minutes)

Approach

  • sometimes it is better to start with brute-force, then spending too much time thinking about a better algorithm

Complexity

  • Time complexity: \(O(n^2)\), n = 1000

  • Space complexity: \(O(n)\)

Code


// 147ms
    fun maxTargetNodes(e1: Array<IntArray>, e2: Array<IntArray>, k: Int): IntArray {
        val (g1, g2) = listOf(e1, e2).map { e ->
            Array(e.size + 1) { ArrayList<Int>() }.also { g ->
                for ((a, b) in e) { g[a] += b; g[b] += a }}}
        fun dfs(x: Int, g: Array<ArrayList<Int>>, p: Int, k: Int): Int =
            if (k < 0) 0 else 1 + g[x].sumOf { if (it == p) 0 else dfs(it, g, x, k - 1) }
        val cnt2 = g2.indices.maxOf { dfs(it, g2, -1, k - 1) }
        return IntArray(g1.size) { cnt2 + dfs(it, g1, -1, k) }
    }


// 67ms
    pub fn max_target_nodes(e1: Vec<Vec<i32>>, e2: Vec<Vec<i32>>, k: i32) -> Vec<i32> {
        let [g1, g2] = [e1, e2].map(|e| { let mut g = vec![vec![]; e.len() + 1];
            for e in e { let (a, b) = (e[0] as usize, e[1] as usize);
            g[a].push(b); g[b].push(a) }; g });
        fn dfs(x: usize, g: &[Vec<usize>], p: usize, k: i32) -> i32 {
            if k < 0 { 0 } else {
                1 + g[x].iter().map(|&s| if s == p { 0 } else { dfs(s, g, x, k - 1)}).sum::<i32>() }}
        let cnt2 = (0..g2.len()).map(|x| dfs(x, &g2, 1001, k - 1)).max().unwrap();
        (0..g1.len()).map(|x| cnt2 + dfs(x, &g1, 1001, k)).collect()
    }


// 95ms
    vector<int> maxTargetNodes(vector<vector<int>>& e1, vector<vector<int>>& e2, int k) {
        int n = size(e1) + 1, m = size(e2) + 1, c2 = 0; vector<vector<int>> g1(n), g2(m);
        for (auto& e: e1) g1[e[0]].push_back(e[1]), g1[e[1]].push_back(e[0]);
        for (auto& e: e2) g2[e[0]].push_back(e[1]), g2[e[1]].push_back(e[0]);
        auto dfs = [&](this const auto& dfs, int x, vector<vector<int>>& g, int p, int k) -> int {
            if (k < 0) return 0; int cnt = 1; for (int s: g[x]) if (s != p) cnt += dfs(s, g, x, k - 1);
            return cnt;
        }; vector<int> r(n);
        for (int i = 0; i < m; ++i) c2 = max(c2, dfs(i, g2, -1, k - 1));
        for (int i = 0; i < n; ++i) r[i] = c2 + dfs(i, g1, -1, k); return r;
    }