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

TIP103 - Unit 7 Session 1 - Graph Algorithm

Uploaded by

Ankit Sahu
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views

TIP103 - Unit 7 Session 1 - Graph Algorithm

Uploaded by

Ankit Sahu
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 75

Lesson Outline (Instructors)

Topic Graphs Algorithms

Learning Objectives Students will be able to…


● Recap on BFS vs DFS graph traversals
● Understand when to use and implement topological sorting
● Explain why topological sorting is useful

Big Questions ● What is topological sorting?


● When is topological sorting used?

Warm Up Problems ● Find All Possible Recipes from Given Supplies

Session Problems ● Course Schedule II


● Course Schedule IV
● Minimum Height Trees
● Reconstruct Itinerary

1
Welcome to Unit 7, Session 1:
Graph Algorithms

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's something you're looking forward to?

2
Graphs Algorithms
TIP103 Unit 7.1
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 Stand Up 0:00 - 0:05
2 Review of BFS/DFS 0:05 - 0:10
3 Topological Sort 0:10 - 0:20
4 UMPIRE Walkthrough 0:20 - 0:35
5 Break 0:35 - 0:40
6 Breakout 0:40 - 1:40
7 Post-Breakout Walkthrough 1:40 - 1:55
8 Wrap Up 1:55 - 2:00

5
Your Feedback

Glows Grows
● Breakout sessions ● Edge lists/sets
● Reviewing/learning ● No TF/coach
graphs ● Java/Python consistency
● Quiet pods

6
5 minutes

Review of BFS/DFS
Review of DFS and BFS
✱ Both are graph traversal algorithms.
✱ They differ in how they determine which node to visit next.

8
DFS
✱ Paths are explored all the way to their leaves before other paths
are considered.
✱ DFS is typically implemented recursively.
✱ There is no guarantee that the first path found is the shortest.

9
Check for Understanding 45 sec

In a depth-first search, starting at node 0, what


node is visited immediately after node 2?
5
A. Node 1
B. Node 3
C. Node 4 1 4
D. It is unspecified.
0

2 3

10
Check for Understanding

In a depth-first search, starting at node 0, what


node is visited immediately after node 2?
5
A. Node 1
B. Node 3
C. Node 4 1 4
D. It is unspecified.
0
Node 3 is visited next because it is node 2's child.
2 3

11
BFS
✱ Paths are explored by level.
✱ BFS is implemented iteratively, maintaining a FIFO queue of nodes
to visit.
✱ The first path found is guaranteed to be the shortest.

12
Check for Understanding 45 sec

In a breadth-first search, starting at node 0,


what node is visited immediately after node 2?
5
A. Node 1
B. Node 3
C. Node 4 1 4
D. It is unspecified.
0

2 3

13
Check for Understanding

In a breadth-first search, starting at node 0,


what node is visited immediately after node 2?
5
A. Node 1
B. Node 3
C. Node 4 1 4
D. It is unspecified.
0
Node 1 is visited because it is at the same level
(relative to node 0) as node 2. 2 3

14
Check for Understanding 45 sec

Which nodes are source nodes (having in-degree 0)?


Select all that apply.
5
A. Node 0
B. Node 1
C. Node 2 1 4
D. Node 3
E. Node 4 0

F. Node 5
2 3
G. None of the above

15
Check for Understanding

Which nodes are source nodes (having in-degree 0)?


Select all that apply.
5
A. Node 0
B. Node 1
C. Node 2 1 4
D. Node 3
E. Node 4 0

F. Node 5
2 3
G. None of the above

16
Check for Understanding 45 sec

Is this a directed acyclic graph?


A. Yes
5
B. No, although it is directed.
C. No, although it does not have a cycle.
D. No, it is undirected and has a cycle. 1 4

2 3

17
Check for Understanding

Is this a directed acyclic graph?


A. Yes
5
B. No, although it is directed.
C. No, although it does not have a cycle.
D. No, it is undirected and has a cycle. 1 4

The edges are directed, and there are no cycles. 0

2 3

18
10 minutes

Topological Sort
Chop
Veggies
Toast Prepare
Bread Eggs

Sauté
Veggies
Butter
Bread
Add Eggs
and Cook

Which tasks
could we
complete first? Plate Food

20
Topological Sorting
✱ An ordering of nodes in a directed acyclic graph (DAG) such that, for each
directed edge from node A to node B, node A appears before node B in the
ordering.

✱ Only DAGs have topological orderings.

✱ A DAG can have multiple topological orderings.

✱ In order to get the topological ordering, we use topological sort.

21
Topological Sorting

1 4

2 3 5 0 1 4 2 3

unsorted graph topologically sorted graph

22
Topological Sorting (DFS)
1. Pick an unvisited source.
2. Do a depth-first traversal starting with that node and only explore
unvisited nodes.
3. After visiting child nodes (post-order), add the parent node to the
front of a list.
4. Repeat until all nodes are visited.
The list will contain a topological sort of the nodes.

23
Topological Sort

1 4

2 3 5 0 1 4 2 3

unsorted graph topologically sorted graph

24
Benefits of Topological Sort
✱ Can be used to
● find the shortest path in a weighted DAG
● determine whether a graph has a cycle
● resolve dependencies (such as determining the order to
perform activities)
✱ Time complexity is O(E + V), where:
● E is the number of edges
● V is the number of vertices
✱ Space complexity is O(V)
● visited set
● stack
25
15 minutes

UMPIRE Walkthrough
Course Schedule https://leetcode.com/problems/course-schedule/

There are a total of numCourses courses you have to take, labeled


from 0 to numCourses - 1. You are given an array prerequisites
where prerequisites[i] = [ai, bi] indicates that you must take
course bi first if you want to take course ai.
For example, the pair [0, 1], indicates that to take course 0 you have
to first take course 1.
Return true if you can finish all courses. Otherwise, return false.

27
U-nderstand
✱ Is prerequisites an edge set?
● Yes, except each pair is in the opposite of the usual order.
● [ai, bi] indicates an edge from bi to ai.
✱ Is prerequisites a DAG?
● Not necessarily! You have to detect if there is a cycle.
✱ How can we tell if there's a cycle?
● Let's draw some pictures…

28
U-nderstand

1 1 1 1

0 0 0 0

2 2 2 2

DAG cyclic cyclic cyclic


happy no sources has source disconnected
case
29
U-nderstand
How can we detect a cycle?
✱ No sources

30
U-nderstand
How can we detect a cycle?
✱ No sources
✱ Not all nodes reachable from sources

1 1

0 0

2 2

31
U-nderstand
How can we detect a cycle?
✱ No sources
✱ Not all nodes reachable from sources
✱ Ancestor and descendant point (possibly indirectly) to each
other.

1 1

0 0

2 2

32
M-atch
✱ Topological sort
✱ Preprocess data
● Convert (backwards) edge set to adjacency list.
● Identify sources.

33
P-lan
1. Preprocess data to build adjacency list and identify sources.
2. Created visited set.
3. Perform DFS from each source:
a. Mark node as visited.
b. Recursively call DFS on all non-visited neighbors.
c. Return false if we identify a cycle. 1
4. If some nodes are unvisited, there must be a cycle.
0

34
P-lan
dfs(i): 1

1. Mark node i as visited.


0
2. Call dfs on any unvisited neighbor.
canFinish(...): 2

1. Preprocess data.
2. For every source, call dfs(source). canFinish()
3. Return true if all nodes visited. dfs(0)

35
P-lan
dfs(i): 1

1. Mark node i as visited.


0
2. Call dfs on any unvisited neighbor.
canFinish(...): 2

1. Preprocess data.
2. For every source, call dfs(source). canFinish()
3. Return true if all nodes visited. dfs(0) → dfs(2)

36
P-lan
dfs(i): 1

1. Mark node i as visited.


0
2. Call dfs on any unvisited neighbor.
canFinish(...): 2

1. Preprocess data.
2. For every source, call dfs(source). canFinish()
3. Return true if all nodes visited. dfs(0) → dfs(2)
dfs(1)

37
P-lan
dfs(i): 1

1. Mark node i as visited.


0
2. Call dfs on any unvisited neighbor.
canFinish(...): 2

1. Preprocess data.
2. For every source, call dfs(source). canFinish()
3. Return true if all nodes visited. dfs(0) → dfs(2)
dfs(1)

38
P-lan
dfs(i): 3

1. Mark node i as visited.


2. Call dfs on any unvisited neighbor.
1
canFinish(...):
1. Preprocess data. 0
2. For every source, call dfs(source).
3. Return true if all nodes visited. 2

canFinish()
dfs(3)

39
P-lan
dfs(i): 3

1. Mark node i as visited.


2. Call dfs on any unvisited neighbor.
1
canFinish(...):
1. Preprocess data. 0
2. For every source, call dfs(source).
3. Return true if all nodes visited. 2

canFinish()
dfs(3) → dfs(1)

40
P-lan
dfs(i): 3

1. Mark node i as visited.


2. Call dfs on any unvisited neighbor.
1
canFinish(...):
1. Preprocess data. 0
2. For every source, call dfs(source).
3. Return true if all nodes visited. 2

canFinish()
dfs(3) → dfs(1) → dfs(2)

41
P-lan
dfs(i): 3

1. Mark node i as visited.


2. Call dfs on any unvisited neighbor.
1
canFinish(...):
1. Preprocess data. 0
2. For every source, call dfs(source).
3. Return true if all nodes visited. 2

canFinish()
dfs(3) → dfs(1) → dfs(2) → dfs(0)
There's a cycle if a neighbor is in the dfs call stack. 42
P-lan
dfs(i): 1

1. Mark node i as visited.


0
2. Call dfs on any unvisited neighbor.
canFinish(...): 2

1. Preprocess data.
2. For every source, call dfs(source). canFinish()
3. Return true if all nodes visited. dfs(0) → dfs(2)
dfs(1)

Having a visited neighbor is fine if it's not in the call stack. 43


P-lan
dfs(i, stack):
1. Mark node i as visited.
2. Iterate over node i's neighbors:
a. If the neighbor is in the stack,
return false.
b. If the neighbor j is not visited:
i. Add node i to the stack.
ii. Call dfs(j, stack)
iii. Remove node i from the stack.
3. Return true if no recursive call reported a cycle.

44
I-mplement/R-eview
Python
class Solution:
def canFinish(self, numCourses: int,
prerequisites: List[List[int]]) -> bool:
# Preprocess data to build adjacency list.
visited = set()
for prereq in prerequisites:
adj = [[] for _ in range(numCourses)]
pre, post = prereq
is_source = [True] * numCourses
adj[pre].append(post)
is_source[post] = False
def dfs(i: int, stack: Set[int] = set()):
visited.add(i)
# Perform dfs from source nodes.
stack.add(i)
for i in range(numCourses):
for neighbor in adj[i]:
if is_source[i]:
if neighbor in visited:
if not dfs(i):
# Are we in a cycle?
return False
if neighbor in stack:
return False
# Make sure all nodes have been visited.
else:
return len(visited) == numCourses
if not dfs(neighbor, stack):
return False
stack.remove(i)
return True

45
Java
public boolean canFinish(int numCourses, int[][] prerequisites) {
Set<Integer> visited = new HashSet<>();
Map<Integer, List<Integer>> adjacencyList = new HashMap<>();
boolean[] isSource = new boolean[numCourses];
class Solution {
Arrays.fill(isSource, true);
boolean dfs(int i, Map<Integer, List<Integer>> adj,
// Preprocess data to build adjacency list.
Set<Integer> visited, Set<Integer> stack) {
for (int[] prereq : prerequisites) {
visited.add(i);
int pre = prereq[1];
stack.add(i);
int post = prereq[0];
for (int neighbor : adj.getOrDefault(i, Collections.emptyList())) {
adjacencyList.computeIfAbsent(pre, k -> new ArrayList<>()).add(post);
if (visited.contains(neighbor)) {
isSource[post] = false;
// Are we in a cycle?
}
if (stack.contains(neighbor)) {
// Perform dfs from source nodes.
return false;
for (int i = 0; i < numCourses; i++) {
}
if (isSource[i]) {
} else {
boolean okay = dfs(i, adjacencyList, visited, new HashSet<>());
// See if recursive call succeeds or finds a cycle.
if (!okay) {
boolean okay = dfs(neighbor, adj, visited, stack);
return false;
if (!okay) {
}
return false;
}
}
}
}
if (visited.size() < numCourses) {
}
// There must not have been enough sources.
stack.remove(i);
return false;
return true;
}
}
return true;
}
}

46
E-valuate
Let V be the number of courses and E the number of prerequisites.

Time Complexity: O(V + E)


✱ Initializing the adjacency list takes time O(V + E).
✱ The depth-first searches will take a total time of O(V + E).

Space Complexity: O(V + E)


✱ The adjacency list is the largest data structure, with size O(V + E).
✱ The stack depth and stack data structure have size O(K), where K is
the longest prerequisite chain, with K <= V.
https://tinyurl.com/cp-tip103-71a
47
I-mplement/R-eview Python
✱ Why is this code so much better class Solution:
UNVISITED = 0

than mine? VISITING = 1


VISITED = -1
✱ The problem didn't ask for the def canFinish(self, n: int, prerequisites: List[List[int]]) -> bool:
topological sort, just whether def dfs(i: int) -> bool:
if color[i] == self.VISITING:
one existed. There was no need return True
if color[i] == self.VISITED:
to identify and start from the return False

sources.
color[i] = self.VISITING
for j in graph[i]:

A topological sort exists if the


if dfs(j):
✱ return True

graph is acyclic. color[i] = self.VISITED

✱ This code just checks if there is return False

a cycle. graph = defaultdict(list)


for u, v in prerequisites:
✱ It also uses 3 values for visited graph[u].append(v)

state, rather than my stack color = [self.UNVISITED] * n


return not any(map(dfs, range(n)))
data structure.

https://leetcode.com/problems/course-schedule/solutions/3331771/python-elegant-short-three-color-dfs/ 49
Lesson
✱ To someone with a
hammer, everything looks
like a nail.
✱ Pause to think about
whether you are doing
more work than
requested.

50
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:
Questions?
○ Course Schedule II [Medium] Post on Slack
○ Course Schedule IV [Medium] and tag:
○ Minimum Height Trees [Medium]
○ Reconstruct Itinerary [Hard] @tip103-tas

● I will go over Minimum Height Trees.

53
Reflection 1 min

What went well in your breakout rooms?


What can you improve?

54
15 minutes

Post-Breakout Walkthrough
Minimum Height Trees https://leetcode.com/problems/minimum-height-trees

A tree is an undirected graph in which any two vertices are connected by exactly one path. In other words, any connected graph without
simple cycles is a tree.

Given a tree of n nodes labelled from 0 to n - 1, and an array of n - 1 edges where edges[i] = [ai, bi] indicates that there is an undirected
edge between the two nodes ai and bi in the tree, you can choose any node of the tree as the root. When you select a node x as the
root, the result tree has height h. Among all possible rooted trees, those with minimum height (i.e. min(h)) are called minimum height
trees (MHTs).

Return a list of all MHTs' root labels. You can return the answer in any order.

The height of a rooted tree is the number of edges on the longest downward path between the root and a leaf.

Constraints:

● 1 <= n <= 2 * 104


● edges.length == n - 1
● 0 <= ai, bi < n
● ai != bi
● All the pairs (ai, bi) are distinct.
● The given input is guaranteed to be a tree and there will be no repeated edges.

56
Example 1

What property does node 1 have that other nodes don't?

57
Example 2

What property do nodes 3 and 4 have that other nodes don't?


58
U-nderstand
✱ The roots will be the nodes furthest from the leaves.
✱ Leaves are nodes that have degree 1.
✱ Can we just throw out the leaves and see what nodes remain?

59
U-nderstand
✱ The roots will be the nodes furthest from the leaves.
✱ Leaves are nodes that have degree 1.
✱ Can we just throw out the leaves and see what nodes remain?

1 2

3 4 5

6 7 8
60
U-nderstand
✱ The roots will be the nodes furthest from the leaves.
✱ Leaves are nodes that have degree 1.
✱ Can we just throw out the leaves and see what nodes remain?

1 2

3 4 5

6 7 8
61
U-nderstand
✱ The roots will be the nodes furthest from the leaves.
✱ Leaves are nodes that have degree 1.
✱ Can we just throw out the leaves and see what nodes remain?

3 5

62
U-nderstand
✱ The roots will be the nodes furthest from the leaves.
✱ Leaves are nodes that have degree 1.
✱ Can we just throw out the leaves and see what nodes remain?
✱ Yes, but it may take several rounds.

63
M-atch
✱ BFS

64
P-lan
1. Preprocess data
a. Build an adjacency list representation.
b. Calculate the degree of each node.
2. Initialize a queue with nodes with degree 1.
3. While nodes are in the queue
a. Copy the queue into a results list in case this is the final level.
b. For all nodes in the queue:
i. Pop the node.
ii. Decrement its neighbors' degrees.
iii. Add neighbors to the queue for the next level (not the
current queue) if they now have degree 1.
4. Return the results list. 65
I-mplementation (page 1)
class Solution {
class Solution:
List<List<Integer>> graph = newArrayList<>();
def findMinHeightTrees(self, n: int,
int[] degree;
edges: List[List[int]]) -> List[int]:
graph = defaultdict(list) public List<Integer> findMinHeightTrees(int n,
degree = [0] * n int[][] edges) {

// Check for trivial graph.


# Check for trivial graph.
if (n == 1) {
if n == 1: return List.of(0);
return [0] }

# Build adjacency lists and degree list. // Build adjacency lists and degree array.
for edge in edges: for (int i = 0; i < n; i++) {
graph.add(new ArrayList<Integer>());
u, v = edge
}
graph[u].append(v) degree = new int[n];
graph[v].append(u) for (int i = 0; i < edges.length; i++) {
degree[u] += 1 graph.get(edges[i][0]).add(edges[i][1]);
degree[v] += 1 graph.get(edges[i][1]).add(edges[i][0]);
degree[edges[i][0]]++;
degree[edges[i][1]]++;
}
66
I-mplementation (page 2)
// Build a queue for BFS.
# Build a queue for BFS.
Queue<Integer> queue = new ArrayDeque<Integer>();
# Add all leaves to the queue.
queue = deque(i for i in range(n) if degree[i] == 1)
// Add all leaves to the queue.
for (int i = 0; i < n; i++) {
# Create a list to hold the results.
if (degree[i] == 1) {
results = []
queue.add(i);
}
}

// Create a list to hold the results.


List<Integer> results = new ArrayList<Integer>();

67
I-mplementation (page 3)
while (!queue.isEmpty()) {
while queue:
// Save the list of nodes at the current level,
# Save the list of nodes at the current level,
// in case this is the final level.
# in case this is the final level.
results = new ArrayList<>(queue);
results = queue.copy()

// Iterate over all the nodes at the current level.


# Iterate over all the nodes at the current level.
int count = queue.size();
count = len(queue)
for (int i = 0; i < count; i++) {
for _ in range(count):
int curr = queue.poll();
curr = queue.popleft()
for (int neighbor : graph.get(curr)) {
for neighbor in graph[curr]:
if (--degree[neighbor] == 1) {
degree[neighbor] -= 1
queue.add(neighbor);
if degree[neighbor] == 1:
}
queue.append(neighbor)
}
}
return results
}
return results;
}

https://leetcode.com/problems/minimum-height-trees/solutions/3811927/clear-commented-java-python3-solution-with-explanation/ 68
E-valuate
Let V be the number of nodes and E the number of edges.

Time Complexity: O(V + E)


✱ Initializing the adjacency list takes time O(V + E).
✱ Queue management: O(V + E).

Space Complexity: O(V + E)


✱ The adjacency list is the largest data structure, with size O(V + E).
✱ The queue has a maximum size of O(V).

69
5 minutes

Wrap Up
Exit Ticket 45 sec

Topological Sorting can be applied to which of the following graphs?


a. Undirected Cyclic Graphs
b. Directed Cyclic Graphs
c. Undirected Acyclic Graphs
d. Directed Acyclic Graphs
e. None of the above

71
Exit Ticket

Topological Sorting can be applied to which of the following graphs?


a. Undirected Cyclic Graphs
b. Directed Cyclic Graphs
c. Undirected Acyclic Graphs
d. Directed Acyclic Graphs
e. None of the above

72
Exit Ticket 45 sec

Topological sort can be implemented by…?


a. DFS
b. BFS
c. both
d. neither

73
Exit Ticket

Topological sort can be implemented by…?


a. DFS
b. BFS
c. both
d. neither

74
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 #1

❒ Next session is Thursday, July 25

❒ 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

75

You might also like