LeetCode Entry

2045. Second Minimum Time to Reach Destination

28.07.2024 hard 2024 kotlin rust

Second min time to travel from 1 to n in time-edged graph stopping every change seconds

2045. Second Minimum Time to Reach Destination hard blog post substack youtube 2024-07-28_11-29_1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/684

Problem TLDR

Second min time to travel from 1 to n in time-edged graph stopping every change seconds #hard #graph #bfs

Intuition

Let’s try to find the 2nd-shortest path with BFS. This solution will be accepted with a one optimization: remove the duplicate nodes from the queue.

Another way to think about the problem is to consider every (path & time) individually and keep track of the best and the 2nd best visited times for each node. Repeat BFS until there are no more improvements in the arrival times.

Approach

Let’s implement both the solutions.

Complexity

  • Time complexity: \(O((EV)^p)\), for the naive BFS, p - second path length, \(O(E + V^2)\) or \(((E + V)log(V))\) for PQ, like for the Dijkstra algorithm

  • Space complexity: \(O(E + V)\)

Code


    fun secondMinimum(n: Int, edges: Array<IntArray>, time: Int, change: Int): Int {
        val g = mutableMapOf<Int, MutableList<Int>>()
        for ((u, v) in edges) {
            g.getOrPut(u) { mutableListOf() } += v; g.getOrPut(v) { mutableListOf() } += u
        }
        val q = ArrayDeque<Int>(); val s = IntArray(n + 1) { -1 }
        q += 1; var found = 0; var totalTime = 0
        while (q.size > 0) {
            repeat(q.size) {
                val c = q.removeFirst()
                if (c == n && found++ > 0) return totalTime
                g[c]?.forEach { if (s[it] != totalTime) { s[it] = totalTime; q += it }}
            }
            totalTime += time + ((totalTime / change) % 2) * (change - (totalTime % change))
        }
        return totalTime
    }


    pub fn second_minimum(n: i32, edges: Vec<Vec<i32>>, time: i32, change: i32) -> i32 {
        let n = n as usize; let (mut g, mut q) = (vec![vec![]; n + 1], VecDeque::from([(1, 0)]));
        let mut s = vec![i32::MAX; n + 1]; let mut ss = s.clone();
        for e in edges {
            let u = e[0] as usize; let v = e[1] as usize;
            g[u].push(v); g[v].push(u)
        }
        while let Some((curr, total_time)) = q.pop_front() {
            let new_time = total_time + time +
                ((total_time / change) % 2) * (change - (total_time % change));
            for &next in &g[curr] { if ss[next] > new_time {
                if s[next] > new_time { ss[next] = s[next]; s[next] = new_time }
                else if s[next] < new_time { ss[next] = new_time }
                q.push_back((next, new_time))
            }}
        }; ss[n]
    }