0% found this document useful (0 votes)
26 views

TIP103 - Unit 7 Session 2 - Graph Algorithm (Continued)

Uploaded by

Ankit Sahu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
26 views

TIP103 - Unit 7 Session 2 - Graph Algorithm (Continued)

Uploaded by

Ankit Sahu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 98

Lesson Outline (Instructors)

Topic Graphs Algorithms (continued)

Learning Objectives Students will be able to…


● Be familiar with the Dijkstra’s Algorithm and Union Find
● Learn how to optimize shortest paths for weighted paths
● Apply Dijkstra’s Algorithm and Union Find to graph-related problems

Big Questions ● What is Dijkstra’s Algorithm?


● What is Union Find?
● How can I optimize shortest paths for weighted paths?

Warm Up Problems ● Find All Possible Recipes from Given Supplies

Session Problems
● Network Delay Time
● Redundant Connection
● Cheapest Flights Within K Stops
● Second Minimum Time to Reach Destination
● Number of Connected Components

1
Graphs Algorithms
(continued)
TIP103 Unit 7.2
Welcome to Unit 7, Session 2:
Graph Algorithms (continued)

1. Turn on your camera.

2. Rename yourself with your pod number, full name, and pronouns:

6 - Montero Hill (she/they)

3. Answer the question below in the chat:

What TV/movie line do you most like to say?

3
As a community, we will...

Be present, physically and mentally

Actively build an inclusive community and space

Practice curiosity and adopt a learning mindset

Ask for help when we need it

Keep our cameras on

4
Agenda
1 Dijkstra's Algorithm 0:00 - 0:10
2 Disjoint Sets and Union Find 0:10 - 0:20
3 UMPIRE Walkthrough 0:20 - 0:30
4 Break 0:35 - 0:40
5 Breakout Sessions 0:40 - 1:40
6 Post-Breakout Walkthrough 1:40 - 1:55
7 Wrap Up 1:55 - 2:00

5
10 minutes

Dijkstra's Algorithm
Check for Understanding 1 min

What is the shortest path from node A to node F?

a. A -> B -> D -> F


b. A -> C -> B -> E -> F
c. A -> F
d. A -> C -> E -> F

7
Check for Understanding 1 min

What is the shortest path from node A to node F?

a. A -> B -> D -> F


b. A -> C -> B -> E -> F
c. A -> F
d. A -> C -> E -> F

A -5-> C -2-> E -3-> F = 10

8
Shortest path without weights

9
Shortest path with weights

10
Why BFS won’t work
✱ Shortest path may not have the fewest edges

How can we modify BFS to expand shorter paths first?


Use a priority queue ordered by the cost to reach a node.
11
Real World Example
In a graph where vertices are cities and weighted edges are roads
between cities, Dijkstra’s Algorithm can be used to find the shortest
route from one city to any other.

12
A Few Applications of Shortest Weighted
Path

✱ Driving directions
✱ Cheap flight itineraries
✱ Network routing
✱ Critical paths in project management

13
Dijkstra's Algorithm
A 0
To find the distance of the shortest path from v0 to other nodes:
2 1
1. Initialize variables
a. Give v0 an initial cost of 0 and all other nodes an initial
∞ B C ∞
cost of ∞. the cheapest known distance from v0.
1

5 D ∞

E ∞

14
Dijkstra's Algorithm
A 0
To find the distance of the shortest path from v0 to other nodes:
2 1
1. Initialize variables
a. Give v0 an initial cost of 0 and all other nodes an initial
∞ B C ∞
cost of ∞. the cheapest known distance from v0.
b. Mark every node as unvisited. 1

5 D ∞

E ∞

15
Dijkstra's Algorithm
A 0
To find the distance of the shortest path from v0 to other nodes:
2 1
1. Initialize variables
a. Give v0 an initial cost of 0 and all other nodes an initial
∞ B C ∞
cost of ∞. the cheapest known distance from v0.
b. Mark every node as unvisited. 1
c. Add v0 to a priority queue to hold nodes sorted by cost.
5 D ∞

E ∞

queue: [(A, 0)]

16
Dijkstra's Algorithm
A 0
To find the distance of the shortest path from v0 to other nodes:
2 1
1. Initialize variables
a. Give v0 an initial cost of 0 and all other nodes an initial
∞ B C ∞
cost of ∞. the cheapest known distance from v0.
b. Mark every node as unvisited. 1
c. Add v0 to a priority queue to hold nodes sorted by cost.
5 D ∞
2. While the queue is not empty
a. Dequeue node vi.
2

E ∞

queue: [(A, 0)]

17
Dijkstra's Algorithm
A 0
To find the distance of the shortest path from v0 to other nodes:
2 1
1. Initialize variables
a. Give v0 an initial cost of 0 and all other nodes an initial
∞ B C ∞
cost of ∞. the cheapest known distance from v0.
b. Mark every node as unvisited. 1
c. Add v0 to a priority queue to hold nodes sorted by cost.
5 D ∞
2. While the queue is not empty
a. Dequeue node vi. (A, 0)
2

E ∞

queue: [ ]

18
Dijkstra's Algorithm
A 0
To find the distance of the shortest path from v0 to other nodes:
2 1
1. Initialize variables
a. Give v0 an initial cost of 0 and all other nodes an initial
∞ B C ∞
cost of ∞. the cheapest known distance from v0.
b. Mark every node as unvisited. 1
c. Add v0 to a priority queue to hold nodes sorted by cost.
5 D ∞
2. While the queue is not empty
a. Dequeue node vi. (A, 0)
2
b. Mark vi as visited.
E ∞

queue: [ ]

19
Dijkstra's Algorithm
A 0
To find the distance of the shortest path from v0 to other nodes:
2 1
1. Initialize variables
a. Give v0 an initial cost of 0 and all other nodes an initial
∞ B C ∞
cost of ∞. the cheapest known distance from v0.
b. Mark every node as unvisited. 1
c. Add v0 to a priority queue to hold nodes sorted by cost.
5 D ∞
2. While the queue is not empty
a. Dequeue node vi. (A, 0)
2
b. Mark vi as visited.
c. For every edge with weight w to an unvisited node vj: E ∞
i. Set cost(vj) to min(cost(vj), cost(vi) + w).
ii. Add vj to the queue with its new weight.

queue: [ ]

20
Dijkstra's Algorithm
A 0
To find the distance of the shortest path from v0 to other nodes:
2 1
1. Initialize variables
a. Give v0 an initial cost of 0 and all other nodes an initial 2
cost of ∞. the cheapest known distance from v0.
B C ∞
b. Mark every node as unvisited. 1
c. Add v0 to a priority queue to hold nodes sorted by cost.
5 D ∞
2. While the queue is not empty
a. Dequeue node vi. (A, 0)
2
b. Mark vi as visited.
c. For every edge with weight w to an unvisited node vj: E ∞
i. Set cost(vj) to min(cost(vj), cost(vi) + w).
ii. Add vj to the queue with its new weight.

queue: [(B, 2)]

21
Dijkstra's Algorithm
A 0
To find the distance of the shortest path from v0 to other nodes:
2 1
1. Initialize variables
a. Give v0 an initial cost of 0 and all other nodes an initial 2 B 1
C
cost of ∞. the cheapest known distance from v0.
b. Mark every node as unvisited. 1
c. Add v0 to a priority queue to hold nodes sorted by cost.
5 D ∞
2. While the queue is not empty
a. Dequeue node vi. (A, 0)
2
b. Mark vi as visited.
c. For every edge with weight w to an unvisited node vj: E ∞
i. Set cost(vj) to min(cost(vj), cost(vi) + w).
ii. Add vj to the queue with its new weight.

queue: [(C, 1), (B, 2)]

22
Dijkstra's Algorithm
A 0
To find the distance of the shortest path from v0 to other nodes:
2 1
1. Initialize variables
a. Give v0 an initial cost of 0 and all other nodes an initial 2 B 1
C
cost of ∞. the cheapest known distance from v0.
b. Mark every node as unvisited. 1
c. Add v0 to a priority queue to hold nodes sorted by cost.
5 D ∞
2. While the queue is not empty
a. Dequeue node vi. (C, 1)
2
b. Mark vi as visited.
c. For every edge with weight w to an unvisited node vj: E ∞
i. Set cost(vj) to min(cost(vj), cost(vi) + w).
ii. Add vj to the queue with its new weight.

queue: [(B, 2)]

23
Dijkstra's Algorithm
A 0
To find the distance of the shortest path from v0 to other nodes:
2 1
1. Initialize variables
a. Give v0 an initial cost of 0 and all other nodes an initial 2 B 1
C
cost of ∞. the cheapest known distance from v0.
b. Mark every node as unvisited. 1
c. Add v0 to a priority queue to hold nodes sorted by cost. D 2
5
2. While the queue is not empty
a. Dequeue node vi. (C, 1)
2
b. Mark vi as visited.
c. For every edge with weight w to an unvisited node vj: E ∞
i. Set cost(vj) to min(cost(vj), cost(vi) + w).
ii. Add vj to the queue with its new weight.

queue: [(B, 2), (D, 2)]

24
Dijkstra's Algorithm
A 0
To find the distance of the shortest path from v0 to other nodes:
2 1
1. Initialize variables
a. Give v0 an initial cost of 0 and all other nodes an initial 2 B 1
C
cost of ∞. the cheapest known distance from v0.
b. Mark every node as unvisited. 1
c. Add v0 to a priority queue to hold nodes sorted by cost. D 2
5
2. While the queue is not empty
a. Dequeue node vi. (B, 2)
2
b. Mark vi as visited.
c. For every edge with weight w to an unvisited node vj: E ∞
i. Set cost(vj) to min(cost(vj), cost(vi) + w).
ii. Add vj to the queue with its new weight.

queue: [(D, 2)]

25
Dijkstra's Algorithm
A 0
To find the distance of the shortest path from v0 to other nodes:
2 1
1. Initialize variables
a. Give v0 an initial cost of 0 and all other nodes an initial 2 B 1
C
cost of ∞. the cheapest known distance from v0.
b. Mark every node as unvisited. 1
c. Add v0 to a priority queue to hold nodes sorted by cost. D 2
5
2. While the queue is not empty
a. Dequeue node vi. (B, 2)
2
b. Mark vi as visited.
c. For every edge with weight w to an unvisited node vj: E 7
i. Set cost(vj) to min(cost(vj), cost(vi) + w).
ii. Add vj to the queue with its new weight.

queue: [(D, 2), (E, 7)]

26
Dijkstra's Algorithm
A 0
To find the distance of the shortest path from v0 to other nodes:
2 1
1. Initialize variables
a. Give v0 an initial cost of 0 and all other nodes an initial 2 B 1
C
cost of ∞. the cheapest known distance from v0.
b. Mark every node as unvisited. 1
c. Add v0 to a priority queue to hold nodes sorted by cost. D 2
5
2. While the queue is not empty
a. Dequeue node vi. (D, 2)
2
b. Mark vi as visited.
c. For every edge with weight w to an unvisited node vj: E 7
i. Set cost(vj) to min(cost(vj), cost(vi) + w).
ii. Add vj to the queue with its new weight.

queue: [(E, 7)]

27
Dijkstra's Algorithm
A 0
To find the distance of the shortest path from v0 to other nodes:
2 1
1. Initialize variables
a. Give v0 an initial cost of 0 and all other nodes an initial 2 B 1
C
cost of ∞. the cheapest known distance from v0.
b. Mark every node as unvisited. 1
c. Add v0 to a priority queue to hold nodes sorted by cost. D 2
5
2. While the queue is not empty
a. Dequeue node vi. (D, 2)
2
b. Mark vi as visited.
c. For every edge with weight w to an unvisited node vj: E 74
i. Set cost(vj) to min(cost(vj), cost(vi) + w).
ii. Add vj to the queue with its new weight.

queue: [(E, 4) (E, 7)]

28
Dijkstra's Algorithm
A 0
To find the distance of the shortest path from v0 to other nodes:
2 1
1. Initialize variables
a. Give v0 an initial cost of 0 and all other nodes an initial 2 B 1
C
cost of ∞. the cheapest known distance from v0.
b. Mark every node as unvisited. 1
c. Add v0 to a priority queue to hold nodes sorted by cost. D 2
5
2. While the queue is not empty
a. Dequeue node vi. (E, 4)
2
b. Mark vi as visited.
c. For every edge with weight w to an unvisited node vj: E 4
i. Set cost(vj) to min(cost(vj), cost(vi) + w).
ii. Add vj to the queue with its new weight.

queue: [ ]

29
Dijkstra's Algorithm
A 0
To find the distance of the shortest path from v0 to other nodes:
2 1
1. Initialize variables
a. Give v0 an initial cost of 0 and all other nodes an initial 2 B 1
C
cost of ∞. the cheapest known distance from v0.
b. Mark every node as unvisited. 1
c. Add v0 to a priority queue to hold nodes sorted by cost. D 2
5
2. While the queue is not empty
a. Dequeue node vi. (E, 4)
2
b. Mark vi as visited.
c. For every edge with weight w to an unvisited node vj: E 4
i. Set cost(vj) to min(cost(vj), cost(vi) + w).
ii. Add vj to the queue with its new weight.

queue: [ ]

30
Complexity of Dijkstra's Algorithm
✱ Time complexity: O(E log V) where
● V is the number of vertices in the graph
● E is the number of edges
● a min-heap is used to implement the priority queue

✱ Space complexity: O(V)


● visited
● cost
● queue

31
10 minutes

Disjoint Sets and Union-Find


Disjoint sets
✱ Disjoint means "non-overlapping"
✱ Examples of disjoint sets
● Even integers and odd integers
● Countries by continent

33
Disjoint sets
✱ Disjoint means "non-overlapping"
✱ Examples of disjoint sets
France Mexico
● Even integers and odd integers
● Countries by continent
✱ We represent the sets as a "forest" Italy
of trees, whose roots are
USA Canada
sometimes called "representative
elements" Germany

34
Disjoint sets
✱ Disjoint means "non-overlapping"
✱ Examples of disjoint sets
France Mexico
● Even integers and odd integers
● Countries by continent
✱ We represent the sets as a "forest" Italy
of trees, whose roots are
USA Canada
sometimes called "representative
elements" Germany

✱ Many problems require grouping


data into disjoint sets

35
parent[0] = 0

Union-Find overview 0: Mexico

✱ Data structure: parent array


● parent[i] holds element i's parent, or
● parent[i] holds i if i is a root 1: France 2: USA

parent[1] = 1 parent[2] = 2
parent[0] = 0

Union-Find overview 0: Mexico

✱ Data structure: parent array


● parent[i] holds element i's parent, or
● parent[i] holds i if i is a root 1: France 2: USA

✱ Functions parent[1] = 1 parent[2] = 2 0


● union(i, j) combines the sets
containing i and j into a single set
union(0, 2)

37
parent[0] = 0

Union-Find overview 0: Mexico

✱ Data structure: parent array


● parent[i] holds element i's parent, or
● parent[i] holds i if i is a root 1: France 2: USA

✱ Functions parent[1] = 1 parent[2] = 0


● union(i, j) combines the sets
containing i and j into a single set
● find(i) finds the root for i 3: Italy

find(1) returns 1

find(2) returns 0
4: Spain
Is find(n) always parent[n]? no
parent[4] = 3
find(4) returns 1
38
Union-Find implementation 1 0: Mexico

parent = [i for i in range(len(nodes))]

def find(x):
while parent[x] != x: 1: France 2: USA
x = parent[x]
return x

def union(x, y):


xroot, yroot = find(x), find(y) 3: Italy
if xroot != yroot:
parent[xroot] = yroot

5: Greece 4: Spain

union(5, 4)

39
Union-Find implementation 1 0: Mexico

parent = [i for i in range(len(nodes))]

def find(x):
while parent[x] != x: 1: France 2: USA
x = parent[x]
return x

def union(x, y):


xroot, yroot = find(x), find(y) 3: Italy
if xroot != yroot:
parent[xroot] = yroot

5: Greece 4: Spain

Time for find/union: O(h), where h is the number of elements in the biggest set. union(4, 5)
What if we could choose the parent that gave the shorter height? 40
Union-Find implementation 2 0: Mexico

parent = [i for i in range(len(nodes))]


rank = [0] * len(nodes)

def find(x): rank[1] = 2 1: France 2: USA


if parent[x] != x:
x = parent[x]
return x

def union(x,y):
xroot, yroot = find(x), find(y) 3: Italy
if xroot != yroot:
if rank[xroot] > rank[yroot]:
parent[yroot] = xroot
else:
parent[xroot] = yroot rank[5] = 0 5: Greece 4: Spain
if rank[xroot] == rank[yroot]:
rank[yroot] += 1
union(4, 5)
Time for union: O(log n), where n is the number of nodes in the graph.
41
We can actually do even better with something called path compression.
Union-Find implementation 3 0: Mexico

parent = [i for i in range(len(nodes))]


rank = [0] * len(nodes)

def find(x): rank[1] = 2 1: France 2: USA


if parent[x] != x:
parent[x] = find(parent[x])
return parent[x]

def union(x,y):
xroot, yroot = find(x), find(y) 3: Italy
if xroot != yroot:
if rank[xroot] > rank[yroot]:
parent[yroot] = xroot
else:
parent[xroot] = yroot rank[5] = 0 5: Greece 4: Spain
if rank[xroot] == rank[yroot]:
rank[yroot] += 1
union(4, 5)

42
Union-Find implementation 3 0: Mexico

parent = [i for i in range(len(nodes))]


rank = [0] * len(nodes)

def find(x): rank[1] = 2 1: France 2: USA


if parent[x] != x:
parent[x] = find(parent[x])
return parent[x]

def union(x,y):
xroot, yroot = find(x), find(y) 3: Italy
if xroot != yroot:
if rank[xroot] > rank[yroot]:
parent[yroot] = xroot
else:
parent[xroot] = yroot rank[5] = 0 5: Greece 4: Spain
if rank[xroot] == rank[yroot]:
rank[yroot] += 1
union(4, 5)

43
Python Java
parent = [i for i in range(len(nodes))] int[] parent = new int[ncells];
rank = [0] * len(nodes) for (int i = 0; i < nodes.length; i++) {
parent[i] = i;
}
def find(x): int[] rank = new int[ncells];
if parent[x] != x:
parent[x] = find(parent[x]) int find(int x) {
if (parent[x] != x) {
return parent[x] parent[x] = find(parent[x]);
}
def union(x,y): return parent[x];
}
xroot, yroot = find(x), find(y)
if xroot != yroot: void union(int x, int y) {
if rank[xroot] > rank[yroot]: int xroot = find(x);
parent[yroot] = xroot int yroot = find(y);
if (xroot != yroot) {
else:
if (rank[xroot] > rank[yroot]) {
parent[xroot] = parent[yroot] parent[yroot] = xroot;
if rank[xroot] == rank[yroot]: } else {
rank[yroot] += 1 parent[xroot] = parent[yroot];
if (rank[xroot] == rank[yroot]) {
rank[yroot]++;
}
}
}
}

44
Union-Find Summary
✱ Union-Find is an algorithm for managing and merging sets.
✱ Most problems that can be solved with Union-Find can also be
solved by DFS or BFS.
✱ The efficiency of the basic implementation can be improved with:
● Union by rank, which keeps the trees balanced.
● Path compression, which shortens the paths to the
representative element.
✱ The space complexity for n elements is O(n).
✱ The time complexity (with the above improvements) is practically
O(1) for each union or find operation.

https://en.wikipedia.org/wiki/Disjoint-set_data_structure#Time_complexity 45
10 minutes

UMPIRE Walkthrough
Number of Islands https://leetcode.com/problems/number-of-islands/

Given an m x n 2D binary grid grid which represents a map of '1's (land) and '0's
(water), return the number of islands.

An island is surrounded by water and is formed by connecting adjacent lands horizontally


or vertically. You may assume all four edges of the grid are all surrounded by water.

Example 1 Example 2

Input: grid = [ Input: grid = [


["1","1","1","1","0"], ["1","1","0","0","0"],
["1","1","0","1","0"], ["1","1","0","0","0"],
["1","1","0","0","0"], ["0","0","1","0","0"],
["0","0","0","0","0"] ["0","0","0","1","1"]
] ]

Output: 1 Output: 3

47
U-nderstand
✱ What are the constraints?
● m == grid.length (number of rows)
● n == grid[i].length (number of columns)
● 1 <= m, n <= 300
● grid[i][j] is '0' or '1'
Input: grid = [
✱ What is the definition of an island? ["1","1","0","0","0"],
["1","1","0","0","0"],
● one or more pieces of land ('1') ["0","0","1","0","0"],
connected horizontally or vertically ["0","0","0","1","1"]
]

48
M-atch
✱ Graph search
● depth-first search
● breadth-first search
✱ Union-find
● The sets are pieces of land.
● They should be merged if adjacent.

49
P-lan
1. Create the initial parent and rank arrays.
Input: grid = [
2. For each element of the grid that is '1': ["1","1","0","1","0"],
a. If its left neighbor is '1', combine them. ["1","1","0","1","0"],
b. If its up neighbor is '1', combine them. ["0","1","1","1","0"],
["0","0","0","1","1"]
c. If its right neighbor is '1', combine them. ]
d. If its down neighbor is '1', combine them.
Output: 1
3. Return the number of sets.

50
P-lan
1. Create the initial parent and rank arrays.
Input: grid = [
2. For each element of the grid that is '1': ["1","1","0","1","0"],
a. If its left neighbor is '1', combine them. ["1","1","0","1","0"],
b. If its up neighbor is '1', combine them. ["0","1","1","1","0"],
["0","0","0","1","1"]
c. If its right neighbor is '1', combine them. ]
d. If its down neighbor is '1', combine them.
Output: 1
3. Return the number of sets.

51
P-lan
1. Create the initial parent and rank arrays.
Input: grid = [
2. For each element of the grid that is '1': ["1","1","0","1","0"],
a. If its left neighbor is '1', combine them. ["1","1","0","1","0"],
b. If its up neighbor is '1', combine them. ["0","1","1","1","0"],
["0","0","0","1","1"]
c. If its right neighbor is '1', combine them. ]
d. If its down neighbor is '1', combine them.
Output: 1
3. Return the number of sets.

52
P-lan
1. Create the initial parent and rank arrays.
Input: grid = [
2. For each element of the grid that is '1': ["1","1","0","1","0"],
a. If its left neighbor is '1', combine them. ["1","1","0","1","0"],
b. If its up neighbor is '1', combine them. ["0","1","1","1","0"],
["0","0","0","1","1"]
c. If its right neighbor is '1', combine them. ]
d. If its down neighbor is '1', combine them.
Output: 1
3. Return the number of sets.

53
P-lan
1. Create the initial parent and rank arrays.
Input: grid = [
2. For each element of the grid that is '1': ["1","1","0","1","0"],
a. If its left neighbor is '1', combine them. ["1","1","0","1","0"],
b. If its up neighbor is '1', combine them. ["0","1","1","1","0"],
["0","0","0","1","1"]
c. If its right neighbor is '1', combine them. ]
d. If its down neighbor is '1', combine them.
Output: 1
3. Return the number of sets.

54
P-lan
1. Create the initial parent and rank arrays.
Input: grid = [
2. For each element of the grid that is '1': ["1","1","0","1","0"],
a. If its left neighbor is '1', combine them. ["1","1","0","1","0"],
b. If its up neighbor is '1', combine them. ["0","1","1","1","0"],
["0","0","0","1","1"]
c. If its right neighbor is '1', combine them. ]
d. If its down neighbor is '1', combine them.
Output: 1
3. Return the number of sets.

55
P-lan
1. Create the initial parent and rank arrays.
Input: grid = [
2. For each element of the grid that is '1': ["1","1","0","1","0"],
a. If its left neighbor is '1', combine them. ["1","1","0","1","0"],
b. If its up neighbor is '1', combine them. ["0","1","1","1","0"],
["0","0","0","1","1"]
c. If its right neighbor is '1', combine them. ]
d. If its down neighbor is '1', combine them.
Output: 1
3. Return the number of sets.

What's inefficient about this?


We don't need to check both the left and right neighbors.

56
P-lan
1. Create the initial parent and rank arrays.
Input: grid = [
2. For each element of the grid that is '1': ["1","1","0","1","0"],
a. If its right neighbor is '1', combine them. ["1","1","0","1","0"],
b. If its down neighbor is '1', combine them. ["0","1","1","1","0"],
["0","0","0","1","1"]
3. Return the number of sets. ]

Output: 1

To implement this, we'll need to convert from a row-col pair


to an index for our parent and rank arrays.

57
Converting from grid position to index

columns
0 1 2 3

rows
1

58
Converting from grid position to index

Row-major ordering

columns
0 1 2 3

0 0 1 2 3

rows
1 4 5 6 7

2 8 9 10 11

index(row, col) =

59
Converting from grid position to index

Row-major ordering

columns
0 1 2 3

0 0 1 2 3

rows
1 4 5 6 7

2 8 9 10 11

index(row, col) = col + row * 4

index(row, col) = col + row * ncols


60
I-mplement
Python
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
nrows = len(grid)
ncols = len(grid[0])
parent = [i for i in range(nrows*ncols)]
self.num_islands = sum(grid[i][j]=='1' for i in range(nrows) for j in range(ncols))

for row in range(nrows):


def find(x):
for col in range(ncols):
while parent[x] != x:
if grid[row][col] == '1':
x = find(parent[x])
i = row*ncols + col
return x
if col > 0 and grid[row][col-1] == '1':
union(i, i - 1)
def union(x,y):
if row > 0 and grid[row-1][col] == '1':
xroot, yroot = find(x), find(y)
union(i, i - ncols)
if xroot != yroot:
parent[xroot] = yroot
return self.num_islands
self.num_islands -= 1

https://leetcode.com/playground/oGKi2YUJ 61
I-mplement
Java int index = 0;
for (int r = 0; r < nrows; r++) {
class Solution { for (int c = 0; c < ncols; c++, index++) {
int[] parent, rank; if (grid[r][c] == '1') {
int nrows, ncols, ncells, nsets; nsets++;
if (r > 0 && grid[r-1][c] == '1') {
public int numIslands(char[][] grid) { // Index one row up is index-ncols
nrows = grid.length; union(index, index - ncols);
ncols = grid[0].length; }
ncells = nrows * ncols; if (c > 0 && grid[r][c-1] == '1') {
parent = new int[ncells]; // Index one left is index-1
union(index, index - 1);
for (int i = 0; i < ncells; i++) { }
parent[i] = i; }
} }
}
return nsets;
Union-Find implementation omitted. }
}
https://leetcode.com/playground/oGKi2YUJ 62
E-valuate
Let V be the number of cells and I the size of the biggest island.

Time Complexity: O(V•log(I))


✱ Initializing the union-find data structures: O(V)
✱ V iterations, with each union taking time O(log I): O(V•log(I))

Space Complexity: O(V)


✱ The union-find data structures: O(V)

63
Break Time!
Take 5 mins to step away from the computer.
Feel free to turn off your camera and return
promptly after 5 mins.
60 minutes

Breakout Sessions
Breakout Rooms 60 minutes

● Today's questions:
○ Network Delay Time (medium)
Questions?
○ Redundant Connection (medium) Post on Slack
○ Cheapest Flights Within K Stops (medium) and tag:
○ Second Minimum Time to Reach Destination (hard)
○ Number of Connected Components (medium, premium) @tip103-tas

● I will go over Network Delay Time and Redundant Connection.

66
Reflection 1 min

How did it go?

67
15 minutes

Post-Breakout Walkthrough
Network Delay Time https://leetcode.com/problems/network-delay-time

You are given a network of n nodes, labeled from 1 to n. You are also
given times, a list of travel times as directed edges times[i] = (ui, vi,
wi), where ui is the source node, vi is the target node, and wi is the time
it takes for a signal to travel from source to target.
We will send a signal from a given node k. Return the minimum time it
takes for all the n nodes to receive the signal. If it is impossible for all
the n nodes to receive the signal, return -1.

69
Network Delay Time
Example 1:
Input: times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2 2
1 1
Output: 2
1 3
1

70
Network Delay Time
Example 2:
1
Input: times = [[1,2,1]], n = 2, k = 1
Output: 1 1

71
Network Delay Time
Example 3:
1
Input: times = [[1,2,1]], n = 2, k = 2
Output: -1 1

72
M-atch
✱ Single-source shortest path in a weighted graph…
✱ Dijkstra's Algorithm

73
P-lan
1. Convert edge set to adjacency list.
2. Create a distance array and a priority queue holding k (distance 0).
3. While the queue is not empty:
a. Extract the node with the minimum distance.
b. For each neighbor of the node:
i. Calculate the cost to reach the neighbor through this node.
ii. If the new cost is lower:
1. Update the neighbor's distance value.
2. Add the neighbor to the priority queue.
4. If any nodes were unreached, return -1 (no path).
5. Otherwise, return the maximum distance.
74
I-mplement/R-eview
Python # Skip if we have already have a better (shorter) path
# to this node.
if time > distance[node]:
import heapq
continue
class Solution:
for neighbor, edge_time in graph[node]:
def networkDelayTime(self, times: List[List[int]],
# Calculate the total time to reach the neighbor.
n: int, k: int) -> int:
total_time = time + edge_time
# Create an adjacency list to represent the graph.
graph = {i: [] for i in range(1, n + 1)}
# If this time is better than its current recorded
for u, v, w in times:
# distance, update the distance and add the neighbor
graph[u].append((v, w))
# to the priority queue.
if total_time < distance[neighbor]:
# Initialize distance array and priority queue (min-heap).
distance[neighbor] = total_time
distance = {node: float('inf') for node in range(1, n + 1)}
heapq.heappush(pq, (total_time, neighbor))
distance[k] = 0
pq = [(0, k)]
# Check if all nodes are reachable and return the maximum
# time taken.
# Iterate over queue.
max_time = max(distance.values())
while pq:
return max_time if max_time < float('inf') else -1
# Extract the node with the minimum distance.
time, node = heapq.heappop(pq)

https://tinyurl.com/cp-tip103-72a 75
while (!pqueue.isEmpty()) {

I-mplement/R-eview // Extract the node in the queue with the minimum total distance.
Edge entry = pqueue.poll();
int time = entry.distance();
int node = entry.node();

Java // Skip it if there is already a shorter path to this node.


if (time > distance[node]) {
class Solution { continue;
record Edge(int distance, int node) {} }
// Otherwise, try to improve paths to neighbors.
public int networkDelayTime(int[][] times, int n, int k) { for (Edge edge : graph.getOrDefault(node, List.of())) {
// The new time to the neighbor will be the time to the
// Create an adjacency list to represent the graph.
// current node plus the distance on the edge.
Map<Integer, List<Edge>> graph = new HashMap<>(); int totalTime = time + edge.distance();
for (int[] time : times) {
Edge edge = new Edge(time[2], time[1]); // If the new time is lower, update the distance for the
// Create ArrayList if it doesn't exist yet. // neighbor and add it to the queue.
graph.computeIfAbsent(time[0], if (totalTime < distance[edge.node()]) {
distance[edge.node()] = totalTime;
x -> new ArrayList<Edge>()).add(edge);
pqueue.add(new Edge(totalTime, edge.node()));
} }
// Initialize distance array. }
int[] distance = new int[n + 1]; // nodes are 1 through n }
Arrays.fill(distance, Integer.MAX_VALUE); // Calculate max time.
int maxTime = Integer.MIN_VALUE;
distance[k] = 0; // start node
for (int i = 1; i <= n; i++) {
maxTime = Math.max(maxTime, distance[i]);
// Initialize priority queue. }
PriorityQueue<Edge> pqueue = new PriorityQueue<>( return maxTime == Integer.MAX_VALUE ? -1 : maxTime;
// This says to compare edges by weight. }
(edge1, edge2) -> edge1.distance() - edge2.distance()); }
pqueue.add(new Edge(0, k));

https://tinyurl.com/cp-tip103-72a 76
E-valuate
Assume V is the number of nodes and E is the number of edges.
✱ Time complexity:
○ Building the adjacency list: O(V + E)
○ Initializing the distance array and priority queue: O(V)
■ Initializing the distance array: O(V)
■ Inserting source node into the priority queue: O(1)
○ Entries in queue: O(E)
■ Loop iterates at most V times. For each iteration, we
perform at most one insertion into the heap: O(log E)
Overall: O(EV log V)

77
E-valuate
Assume V is the number of nodes and E is the number of edges.
✱ Space complexity:
○ Adjacency list: O(V+E)
○ Distance array: O(V)
○ Priority queue: O(E)

Overall: O(V+E)

https://tinyurl.com/cp-tip103-72a
78
Redundant Connection https://leetcode.com/problems/redundant-connection/

In this problem, a tree is an undirected graph that is connected and has


no cycles.
You are given a graph that started as a tree with n nodes labeled from 1 to
n, with one additional edge added. The added edge has two different
vertices chosen from 1 to n, and was not an edge that already existed. The
graph is represented as an array edges of length n where edges[i] = [ai,
bi] indicates that there is an edge between nodes ai and bi in the graph.
Return an edge that can be removed so that the resulting graph is a tree
of n nodes. If there are multiple answers, return the answer that occurs last
in the input.

79
Redundant Connection https://leetcode.com/problems/redundant-connection/

Example 1:
Input: edges = [[1,2], [1,3], [2,3]]
Output: [2,3] 1 2

80
Redundant Connection https://leetcode.com/problems/redundant-connection/

Example 1:
Input: edges = [[1,2], [1,3], [2,3]]
Output: [2,3] 1 2

81
Redundant Connection https://leetcode.com/problems/redundant-connection/

Example 1:
Input: edges = [[1,2], [1,3], [2,3]]
Output: [2,3] 1 2

82
Redundant Connection https://leetcode.com/problems/redundant-connection/

Example 1:
Input: edges = [[1,2], [1,3], [2,3]]
Output: [2,3] 1 2

83
M-atch
✱ We want to keep adding edges until doing so would add a cycle.
✱ Union-Find can keep track of which nodes are connected.

84
P-lan
1. Initialize Union-Find data structures.
2. Iterate over edges:
a. Extract nodes a and b from edges.
b. If find(a) == find(b), they are already connected, so adding
another edge would make a cycle. Return the current edge.
c. Otherwise, union(a, b) to indicate that they are connected.

edges = [[1,2], [1,3], [2,3]] 1 2

3
85
P-lan
1. Initialize Union-Find data structures.
2. Iterate over edges:
a. Extract nodes a and b from edges.
b. If find(a) == find(b), they are already connected, so adding
another edge would make a cycle. Return the current edge.
c. Otherwise, union(a, b) to indicate that they are connected.

edges = [[1,2], [1,3], [2,3]] 1 2

3
86
P-lan
1. Initialize Union-Find data structures.
2. Iterate over edges:
a. Extract nodes a and b from edges.
b. If find(a) == find(b), they are already connected, so adding
another edge would make a cycle. Return the current edge.
c. Otherwise, union(a, b) to indicate that they are connected.

edges = [[1,2], [1,3], [2,3]] 1 2

3
87
P-lan
1. Initialize Union-Find data structures.
2. Iterate over edges:
a. Extract nodes a and b from edges.
b. If find(a) == find(b), they are already connected, so adding
another edge would make a cycle. Return the current edge.
c. Otherwise, union(a, b) to indicate that they are connected.

edges = [[1,2], [1,3], [2,3]] 1 2

3
88
I-mplement/R-eview Java
class Solution {

Python int[] parent;


int[] rank;
class Solution:
def findRedundantConnection(self, public int[] findRedundantConnection(int[][] edges) {
edges: List[List[int]]) -> List[int]: // Initialize Union-Find data structures.
n = len(edges) parent = new int[edges.length];
parent = [i for i in range(n)] for (int i = 0; i < edges.length; i++) {
rank = [0] * n parent[i] = i;
}
for edge in edges: rank = new int[edges.length];
a, b = edge[0] - 1, edge[1] - 1
if find(a) == find(b): // Add edges until doing so would introduce a cycle.
return edge for (int[] edge : edges) {
else: int a = edge[0] - 1;
union(a, b) int b = edge[1] - 1;
if (find(a) == find(b)) {
return None return edge;
}
union(a, b);
}
return null; // unreachable code
}
}
https://tinyurl.com/cp-tip103-72b 89
E-valuate
Assume V is the number of nodes and E is the number of edges. For
this problem, V = E.
✱ Time complexity: O(V)
○ Initializing the Union-Find data structures: O(V)
○ Iterating over the edges: O(E)
✱ Space complexity: O(V)

https://tinyurl.com/cp-tip103-72b 90
5 minutes

Wrap Up
Exit Ticket 1 min

Given an undirected graph with negative edge weights, will Dijkstra's


algorithm find the shortest path between two nodes correctly?
a. Yes
b. No

92
Exit Ticket

Given an undirected graph with negative edge weights, will Dijkstra's


algorithm find the shortest path between two nodes correctly?
a. Yes
b. No
Dijkstra's Algorithm relies on the fact that all edges are non-negative,
meaning that adding an edge can never make a path shorter. This is
not the case with negative edge weights.

93
Exit Ticket 1 min

What is the benefit of considering rank in Union-Find?


A. It keeps the sizes of the sets as equal as possible.
B. It minimizes the distance from nodes to their representative
elements.
C. It enables you to tell the order in which nodes were added to the
set.
D. It enables you to tell the order in which nodes were created.

94
Exit Ticket

What is the benefit of considering rank in Union-Find?


A. It keeps the sizes of the sets as equal as possible.
B. It minimizes the distance from nodes to their representative
elements.
C. It enables you to tell the order in which nodes were added to the
set.
D. It enables you to tell the order in which nodes were created.

95
Exit Ticket 1 min

Which algorithms could be used to identify all nodes in a graph that


are reachable from a source? Select all that apply.
A. Breadth-first search
B. Depth-first search
C. Union-Find
D. Dijkstra's Algorithm

96
Exit Ticket

Which algorithms could be used to identify all nodes in a graph that


are reachable from a source? Select all that apply.
A. Breadth-first search
B. Depth-first search
C. Union-Find
D. Dijkstra's Algorithm
Any of these algorithms can be used.

97
Before you leave...
❒ Complete the Session Survey [5 min]
○ Course: [TIP103-S1] Advanced Technical Interview Prep (Section 1)

○ Week number: 7 (7/23 - 7/27)

○ Session #2

❒ Next session is Tuesday, July 30

❒ Complete by 11:59pm PDT the night before next week's first session
○ HackerRank assessment → Link on the assignment tab
○ Warm up for next unit → Link on the warmup tab

98

You might also like