Second Minimum time to reach destination in Java

A bi-directional connected graph with n vertices labeled from 1 to n is called a city. Every minute, the color of the traffic signal at each vertex changes. Walking around any edge takes minutes. The value that is smallest and yet strictly greater than the minimum is the second minimum value. The number of times it takes to move from vertex 1 to vertex n, with all signals turning green at the start, is divided to find the second minimum time.

Example 1:

Second Minimum time to reach destination in Java

Input: n = 5, edges = [[1,2],[1,3],[1,4],[3,4],[4,5]], time = 3, change = 5

Output: 13

Explanation: 

Second Minimum time to reach destination in Java

Path 1:

The duration is as follows: - Begin at 1, time elapsed=0

1 -> 4: 3 minutes, 3 minutes of elapsed time

4 -> 5: 3 minutes; 6 minutes have passed. 

So, six minutes is the bare minimum of time required. 

Begin at 1; time elapsed equals 0. 

Path 2:

1 -> 3: 3 minutes, 3 minutes have passed.

3 -> 4: 3 minutes, 6 minutes have passed.

Wait for 4 minutes at 4; the time elapsed is 10. 

4 -> 5: 3 minutes; 13 minutes have passed. 

13 minutes is the second minimum time as a result.

Using Naive Approach

The naive approach to finding the second minimum distance from node 1 to node n in a graph uses Breadth-First Search (BFS). It initializes an adjacency list representation and populates it with input edges. BFS is used to find the minimum and second minimum distances, and a queue is maintained to explore nodes. The total time required to traverse the second minimum distance is calculated by iterating over the distance and applying the 'change' condition.

Here's an implementation of finding a second minimum time to reach distance using a naive approach:

FileName:NaiveSolution.java

import java.util.*;

public class NaiveSolution {

    // Method to find the second minimum time to reach node n using a naive approach

    public int secondMinimum(int n, int[][] edges, int time, int change) {

        // Create an adjacency list representation of the graph

        List<Integer>[] g = new List[n + 1];

        Arrays.setAll(g, k -> new ArrayList<>());

        for (int[] e : edges) {

            int u = e[0], v = e[1];

            g[u].add(v);

            g[v].add(u);

        }

        // Use a deque for BFS traversal

        Deque<int[]> q = new LinkedList<>();

        q.offerLast(new int[]{1, 0});

        // Initialize an array to store the minimum and second minimum distances to each node

        int[][] dist = new int[n + 1][2];

        for (int i = 0; i < n + 1; ++i) {

            Arrays.fill(dist[i], Integer.MAX_VALUE);

        }

        dist[1][1] = 0;

        // Perform BFS traversal to find the minimum and second minimum distances

        while (!q.isEmpty()) {

            int[] e = q.pollFirst();

            int u = e[0], d = e[1];

            for (int v : g[u]) {

                if (d + 1 < dist[v][0]) {

                    dist[v][0] = d + 1;

                    q.offerLast(new int[]{v, d + 1});

                } else if (dist[v][0] < d + 1 && d + 1 < dist[v][1]) {

                    dist[v][1] = d + 1;

                    if (v == n) {

                        break;

                    }

                    q.offerLast(new int[]{v, d + 1});

                }

            }

        }

        // Calculate the total time required to reach node n using the second minimum distance

        int ans = 0;

        for (int i = 0; i < dist[n][1]; ++i) {

            ans += time;

            if (i < dist[n][1] - 1 && (ans / change) % 2 == 1) {

                ans = (ans + change) / change * change;

            }

        }

        return ans;

    }

    public static void main(String[] args) {

        NaiveSolution solution = new NaiveSolution();

        int n = 5;

        int[][] edges = {{1, 2}, {1, 3}, {1, 4}, {3, 4}, {4, 5}};

        int time = 3;

        int change = 5;

        // Call the secondMinimum method and print the result

        int result = solution.secondMinimum(n, edges, time, change);

        System.out.println("Result: " + result);

    }

}

Output:

Result: 13

Complexity analysis: The naive approach to graph analysis has a time complexity of O(V + E), primarily determined by the Breadth-First Search (BFS) traversal. In the worst case, each edge and node is visited once, resulting in a time complexity of O(V + E). The space complexity is determined by the data structures used to store the graph and distances, with the adjacency list being the dominant factor. The space complexity is O(V + E), resulting in a total time complexity of O(V + E).

Using Optimized approach

The optimized approach to graph traversal aims to find the second minimum distance from node 1 to node n in a graph represented by an adjacency list. It improves the efficiency of updating the second minimum distance during the Breadth-First Search (BFS) traversal. The code initializes an adjacency list representation, uses BFS to find the minimum and second minimum distances, and calculates the total time required to traverse the second minimum distance. The key optimization is the update of the second minimum distance within the BFS loop itself.

Here's an implementation of finding a second minimum time to reach distance using an optimized approach:

FileName:OptimizedSolution.java

import java.util.*;

public class OptimizedSolution {

// Method to find the second minimum time to reach node n

    public int secondMinimum(int n, int[][] edges, int time, int change) {

        List<Integer>[] g = new List[n + 1];

        Arrays.setAll(g, k -> new ArrayList<>());

        for (int[] e : edges) {

            int u = e[0], v = e[1];

            g[u].add(v);

            g[v].add(u);

        }

        // Use a deque for BFS traversal

        Deque<int[]> q = new LinkedList<>();

        q.offerLast(new int[]{1, 0});

        int[][] dist = new int[n + 1][2];

        for (int i = 0; i < n + 1; ++i) {

            Arrays.fill(dist[i], Integer.MAX_VALUE);

        }

        dist[1][1] = 0;

        // Perform BFS traversal to find the minimum and second minimum distances

        while (!q.isEmpty()) {

            int[] e = q.pollFirst();

            int u = e[0], d = e[1];

            for (int v : g[u]) {

                if (d + 1 < dist[v][0]) {

                    dist[v][1] = dist[v][0]; // Update second minimum

                    dist[v][0] = d + 1;

                    q.offerLast(new int[]{v, d + 1});

                } else if (dist[v][0] < d + 1 && d + 1 < dist[v][1]) {

                    dist[v][1] = d + 1;

                    if (v == n) {

                        break;

                    }

                    q.offerLast(new int[]{v, d + 1});

                }

            }

        }

        // Calculate the total time required to reach node n using the second minimum distance

        int ans = 0;

        for (int i = 0; i < dist[n][1]; ++i) {

            ans += time;

            if (i < dist[n][1] - 1 && (ans / change) % 2 == 1) {

                ans = (ans + change) / change * change;

            }

        }

        return ans;

    }

     public static void main(String[] args) {

        int n = 5;

        int[][] edges = {{1, 2}, {1, 3}, {1, 4}, {3, 4}, {4, 5}};

        int time = 3;

        int change = 5;

        // Create an instance of the OptimizedSolution class

        OptimizedSolution optimizedSolution = new OptimizedSolution();

        // Call the secondMinimum method and print the result

        int optimizedResult = optimizedSolution.secondMinimum(n, edges, time, change);

        System.out.println("Result: " + optimizedResult);

    }

}

Output:

Result: 13

Complexity analysis: The optimized approach to graph traversal calculates the total time using the Breadth-First Search (BFS) traversal. The time complexity is O(V + E), where V is the number of vertices and E is the number of edges. The time complexity is O(V + E) due to the constant number of iterations in the loop. The space complexity is O(V + E) due to the data structures used to store the graph and distances. The optimized approach maintains the BFS traversal to find the minimum and second minimum distances efficiently, updating the second minimum distance within the BFS loop.