Solution: Network Delay Time

Statement#

A network of n nodes labeled 11 to nn is provided along with a list of travel times for directed edges represented as times[i]=(xi, yi, ti)times[i]=(x_i​, \space y_i​, \space t_i​), where xix_i​ is the source node, yiy_i​ is the target node, and tit_i​ is the delay time from the source node to the target node.

Considering we have a starting node, k, we have to determine the minimum time required for all the remaining for n - 1 nodes to receive the signal. Return 1-1 if it is not possible for all n - 1 nodes to receive the signal.

Constraints:

  • 11 \leq k \leq n \leq 100100
  • 11 \leq times.length \leq 60006000
  • times[i].length ==3== 3
  • 1x,y1 \leq x, y \leq n
  • xx !=!= yy
  • 0t1000 \leq t \leq 100
  • Unique pairs of (x,y)(x, y), which means that there should be no multiple edges

Solution#

So far, you have probably brainstormed some approaches and have an idea of how to solve this problem. Let’s explore some of these approaches and figure out which one to follow based on considerations such as time complexity and any implementation constraints.

Naive approach#

The naive approach is to use a simple brute force method. The algorithm would start by initializing all distances (time to travel from source to target node) to infinity, representing disconnection between the two nodes. Then, each node would use a nested loop to go through all other nodes and update their distances using the given travel times. If there is no connection between a source and a target node, its distance will not be updated. After updating all distances, the algorithm would find the maximum distance among all nodes, representing the minimum time it takes for all nodes to receive the signal. If a node that cannot be reached from node k exists, it means the distance is infinity, and it will return -1.

This approach has a time complexity of O(n2)O(n^2), where nn is the number of nodes in the graph.

Optimized approach using Dijkstra’s algorithm#

Dijkstra’s algorithm is widely used for finding the shortest path between nodes in a graph. This makes it ideal for finding the minimum delay time in a network.

We will use an adjacency dictionary. The source node will be used as key, and the value is a list of tuples that have the destination node and the time for the signal to travel from source to destination node. A priority queue is initialized with time initialized to 00 and starting node k as a tuple. The priority queue ensures that the node with the minimum time is retrieved in each iteration. We will iterate over the priority queue to traverse the nodes in the network. If the node is not visited, the time of the retrieved node is compared to the current delay time and updated accordingly. The neighbors of the retrieved node are found using the adjacency dictionary and are added to the queue with their times updated by adding the delay time from the retrieved node.

Finally, if all the network nodes have been visited, we will return the computed time. Otherwise, 1-1 will be returned.

The slides below illustrate how we would like the algorithm to run:

Created with Fabric.js 3.6.6 Four nodes labeled 1 to 4 are provided along with a list of travel times. Weneed to find the minimum time it takes from node 3 (k) to reach every nodein the graph.

1 of 23

Created with Fabric.js 3.6.6 adjacency An adjacency dictionary is created where the key is the source node, and thevalue is a list of tuples containing the destination node and the time that areretrieved from the times input list.

2 of 23

Created with Fabric.js 3.6.6 adjacency 1 : [] Since node 1 is not present in the times list as a source node, an empty list will be added as its value in the adjacency dictionary.

3 of 23

Created with Fabric.js 3.6.6 adjacency 1 : [] 2 : [(1, 1)] For node 2, the destination node is 1, and its travel time is 1. Both are addedinto the adjacency dictionary.

4 of 23

Created with Fabric.js 3.6.6 adjacency 1 : [] 2 : [(1, 1)] 3 : [(2, 1), (4, 2)] Similarly, for node 3, both the paths for node 2 and 4 are added with theirrespective times.

5 of 23

Created with Fabric.js 3.6.6 adjacency 1 : [] 2 : [(1, 1)] 3 : [(2, 1), (4, 2)] 4 : [] Since node 4 is not present in the times list as a source node, an empty list will be added as its value in the adjacency dictionary.

6 of 23

Created with Fabric.js 3.6.6 adjacency 1 : [] 2 : [(1, 1)] 3 : [(2, 1), (4, 2)] 4 : [] pq (0, 3) The priority queue (pq) will be initialized with time 0 and node k as a tuple.

7 of 23

Created with Fabric.js 3.6.6 adjacency 1 : [] 2 : [(1, 1)] 3 : [(2, 1), (4, 2)] 4 : [] pq (0, 3) visited delays 0 A visited set is created to keep track of the nodes that have alreadybeen processed. The delays variable is created to store the delay time.

8 of 23

Created with Fabric.js 3.6.6 adjacency 1 : [] 2 : [(1, 1)] 3 : [(2, 1), (4, 2)] 4 : [] visited pq (0, 3) Current node = 3 Current time = 0 delays 0 At each iteration, we will remove the node with the smallest time from pq. Inthis case, there is currently only one node in the queue, which is (0, 3).

9 of 23

Created with Fabric.js 3.6.6 adjacency 1 : [] 2 : [(1, 1)] 3 : [(2, 1), (4, 2)] 4 : [] visited 3 Current node = 3 pq Current time = 0 delays 0 Now, we will check if the node is present in the visited set. Since it is not, wewill add it to the visited set. The delays variable will be updated by takingthe maximum of its current value and the time associated with the node.

10 of 23

Created with Fabric.js 3.6.6 visited 3 pq adjacency 1 : [] 2 : [(1, 1)] 3 : [(2, 1), (4, 2)] 4 : [] Current node = 3 Current time = 0 Now, the neighbors of node 3 will be retrieved from the adjacency dictionary,which are (2, 1) and (4, 2). They will be checked to see if they are present inthe visited set. delays 0

11 of 23

Created with Fabric.js 3.6.6 adjacency 1 : [] 2 : [(1, 1)] 3 : [(2, 1), (4, 2)] 4 : [] visited 3 pq (1, 2) (2, 4) Current node = 3 Current time = 0 Since they are not, we will add them to the pq by computing their new time asthe sum of the time of node 3 and the time of each respective neighbor. delays 0

12 of 23

Created with Fabric.js 3.6.6 adjacency 1 : [] 2 : [(1, 1)] 3 : [(2, 1), (4, 2)] 4 : [] visited 3 pq (1, 2) (2, 4) Current node = 2 Current time = 1 We will remove the node with the smallest time from pq, and in this case, itwill be (1, 2). delays 0

13 of 23

Created with Fabric.js 3.6.6 adjacency 1 : [] 2 : [(1, 1)] 3 : [(2, 1), (4, 2)] 4 : [] Current node = 2 pq (2, 4) visited 3 2 Current time = 1 delays 1 Now, we will check if the node is present in the visited set. Since it is not, wewill add it to the visited set. The delays variable will be updated by takingthe maximum of its current value and the time associated with the node.

14 of 23

Created with Fabric.js 3.6.6 Current node = 2 pq (2, 4) visited 3 2 adjacency 1 : [] 2 : [(1, 1)] 3 : [(2, 1), (4, 2)] 4 : [] Current time = 1 Now, the neighbor of node 2 will be retrieved from the adjacency dictionary,which is (1, 1). It will be checked to see if it is present in the visited set. delays 1

15 of 23

Created with Fabric.js 3.6.6 Current node = 2 visited 3 2 adjacency 1 : [] 2 : [(1, 1)] 3 : [(2, 1), (4, 2)] 4 : [] pq (2, 4) (2, 1) Current time = 1 delays 1 Since it is not, we will add it to the pq by computing its new time by addingthe time of node 2.

16 of 23

Created with Fabric.js 3.6.6 visited 3 2 adjacency 1 : [] 2 : [(1, 1)] 3 : [(2, 1), (4, 2)] 4 : [] pq (2, 4) (2, 1) Current node = 1 Current time = 2 delays 1 We will remove the node with the smallest time from pq, and in this case, it can be any one from (2, 4) or (2, 1). We will remove (2, 1) because it wasadded recently.

17 of 23

Created with Fabric.js 3.6.6 adjacency 1 : [] 2 : [(1, 1)] 3 : [(2, 1), (4, 2)] 4 : [] Current node = 1 pq (2, 4) visited 3 2 1 Current time = 2 delays 2 Now, we will check if the node is present in the visited set. Since it is not, wewill add it to the visited set. The delays variable will be updated by takingthe maximum of its current value and the time associated with the node.

18 of 23

Created with Fabric.js 3.6.6 Current node = 1 pq (2, 4) visited 3 2 1 adjacency 1 : [] 2 : [(1, 1)] 3 : [(2, 1), (4, 2)] 4 : [] Current time = 2 delays 2 Now, the neighbor of node 1 will be retrieved from the adjacency dictionary,which is an empty list. Therefore, we will continue with our next iteration.

19 of 23

Created with Fabric.js 3.6.6 visited 3 2 1 adjacency 1 : [] 2 : [(1, 1)] 3 : [(2, 1), (4, 2)] 4 : [] pq (2, 4) Current node = 4 Current time = 2 We will remove the node with the smallest cost from pq, and in this case, thereis currently only one node in the queue, which is (2, 4). delays 2

20 of 23

Created with Fabric.js 3.6.6 adjacency 1 : [] 2 : [(1, 1)] 3 : [(2, 1), (4, 2)] 4 : [] Current node = 4 pq visited 3 2 1 4 Current time = 2 delays 2 Now, we will check if the node is present in the visited set. Since it is not, wewill add it to the visited set. The delays variable will be updated by takingthe maximum of its current value and the time associated with the node.

21 of 23

Created with Fabric.js 3.6.6 Current node = 4 pq visited 3 2 1 4 adjacency 1 : [] 2 : [(1, 1)] 3 : [(2, 1), (4, 2)] 4 : [] Current time = 2 delays 2 Now, the neighbor of node 4 will be retrieved from the adjacency dictionary,which is an empty list. Therefore, we will continue with our next iteration.

22 of 23

Created with Fabric.js 3.6.6 pq visited 3 2 1 4 adjacency 1 : [] 2 : [(1, 1)] 3 : [(2, 1), (4, 2)] 4 : [] visited.length = 4 = n delays 2 Since pq is now empty, we will exit the loop. The function will then comparethe length of the visited set with the number of nodes n. In this case, theyare equal, so the function will return the value stored in the delays variable,which is 2.

23 of 23

Note: In the following section, we will gradually build the solution. Alternatively, you can skip straight to the Just the code section.

Step-by-step solution construction#

Let’s start our solution by constructing the adjacency dictionary. The source node will be the key, whereas the destination node and the corresponding time required to travel from the source to the destinate node are going to be part of the value list. The source nodes not present in the adjacency dictionary will return an empty list.

Creating adjacency dictionary

In the following code, we are creating a priority queue in line 13 and adding the source node with a delay time of 00 in line 15. The priority queue stores the delay time of each node as the first element of each tuple and the node as the second element (time, node). This queue keeps track of which node needs to be processed next, with the node having the minimum delay time being processed first.

Additionally, we also initialize an empty set called visited in line 16, which will be used to track of nodes that have already been processed. The delays variable is initialized to 00 and will be used to keep track of the delay time among all the nodes in the network.

Creating a priority queue and a visited set

We will start a loop that continues until the pq is not empty (lines 19–41). In the loop, deqeue the tuple with the minimum delay time. Then we will check if this node has already been processed, i.e., it is present in the visited set; see line 27.

If it has not been processed, the algorithm adds the node to the visited set (line 30) and updates the delays value (line 31) if the node’s delay time is greater than the current delays value.

Next, the neighbors of the current node are retrieved from the adjacency dictionary (line 32), and for each unvisited neighbor, its delay time (line 40) is computed by adding the delay time of the current node and the delay time between the current node and the neighbor. These neighbors are then added to the pq (line 41) so they can be processed in the next iteration of the while loop.

Iterating through priority queue

Finally, we will check if the number of nodes visited equals the total number of nodes, n (line 44). If TRUE, we will return the delay time stored in the delays (line 45); otherwise, return 1-1. This step ensures that the algorithm has processed all the nodes. If all nodes have not been processed, it indicates that some nodes in the network are not reachable from the source node.

Checking if all nodes visited or not

Just the code#

Here’s the complete solution to this problem:

Network Delay Time

Solution summary#

The algorithm can be summarized in the following steps:

  1. Create an adjacency dictionary to store the information of the nodes and their edges.

  2. Use a priority queue to store the nodes and their delay times. Initialize the queue with the source node and a delay time of 0.

  3. Use a visited set to track the nodes that have already been processed.

  4. Process the nodes from the priority queue by first visiting the node with the smallest delay time and updating the delay time if necessary.

  5. Add the unvisited neighbors of the processed node to the priority queue with their new delay times.

  6. Return the delay time if all nodes have been processed. Otherwise, return 1-1.

Time complexity#

This algorithm takes O(ElogN)O(E\log N), where EE is the total number of edges, and NN is the number of nodes in the network since push and pop operations on the priority queue take O(logN)O(\log N) time.

Space complexity#

The space complexity is O(N+E)O(N+E), where NN is the number of nodes in the graph, and EE is the number of edges required by the adjacency dictionary and priority queue.

Network Delay Time

Paths in Maze That Lead to Same Room