Intro to Graph
Video: https://www.youtube.com/watch?v=zaBhtODEL0w&t=261s
Definetion A directed graph is a set V of vertices and a set E of edges. Given an edge e = (u,v), the vertex u is its source, and v is its sink
A path in a directed graph from u to vertex v is a sequence of vertices
A directed acyclic graph (DAG) is a directed graph in which there are no cycles (paths which contains one or more edges and which begin and end at the same vertex).
[Related Problems]
- Matrix problems
- Geometric problems
- Consider using a graph when you need to analyze any binary relationship
- BFS can be used to compute distances from the start vertex and DFS can be used to check for the presence of cycles
Connected Graph
- If G is an undirected graph, vertices u and v are said to be connected if G contains a path from u to v.
- A graph is said to be connected if every pair of vertices in the graph is connected
- A connected component is a maximal set of vertices C such that each pair of vertices in C is connected in G
- A directed graph is called weakly connected if replacing all of its directed edges with undirected edges produces an undirected graph that is connected.
Representation
Adjacency lists and Adjacency matrix
Spanning tree
Given a graph G = (V,E), if the graph G’ = (V, E’) where E’ belongs to E is a tree, then G’ is referred to as a spanning tree of G.
DFS
Goes Deep to children before going broad to neighbors. Mark visited node to avoid cycles.
[Key Concept] Use Stack, Use a Mark to mark if a node is visited.
- Visit node A, mark A as visited add A to the top of stack
- Find A’s unvisited B, visit B, repeat first step
- If all of the chilren are visited, pop node off the stack
[Related Problems]
- Anaylizing structure. i.e. Looking for cycles or connected components
- Some graph problems are
133. Clone Graph
Leetcode: https://leetcode.com/problems/clone-graph/description/
Solution
- Use a Map to track visited nodes. If visited, return the node.
- Clone node, and put node into visited map.
- Clone all the neighbors of the node and link them to the cloned node.
1 | public class Solution { |
138. Copy List with Random Pointer
Leetcode: https://leetcode.com/problems/copy-list-with-random-pointer/description/
Solution same as the above problem.
1 | public class Solution { |
Team Match problem
Goal: Given team A and B, is there a sequence of teams starting with A and ending with B such that each team in the sequence has beaten the next team in the sequence?
1 | MatchResult = collections.namedtupple('MatchResult', ('winning_team', 'losing_team')) |
Tarjan’s Algorithm
Tarjan’s Algorithm is used in finding strongly connected components.
Strongly Connected Components (SCC) can be thought of as self-contained cycles within a directed graph where every vertex in a given cycle can reach every other vertex in the same cycle.
Low-link value of a node is the smallest[lowest] node id reachable from that node when doing a DFS (including itself)
Flaw: the low-link value might be dependant on the start point of dfs traversal.
To fix the flaw: use a stack(set) of valid nodes:
- Nodes are added to the stack of valid nodes as they’re explored for the first time
- Nodes are removed from the stack each time a complete SCC is found
New low-link update condition:
- If
u
andv
are nodes in a graph and we’re currently onu
: - To update
u
‘s low-link value to nodev
‘s low-link value there has to be a valid path fromu
tov
and v
must be on the stack
Time complexity: linear O(V+E)
1 | UNVISITED = -1 |
BFS
[Key Concept] Use Queue, Use a Mark to mark if a node is visited.
Goes Broad to neighbors before goes deep. Use a Queue to add all the children of the nodes into the queue maintain the right order.
- Visit node A, mark A as visited, add A to queue
- Visit A’s unvisited child B, repeat step A
- If all the chilren are visited, pop node from queue, and make that node the current node, repeat step 1
Shortest path problems:
- Binary Tree Level Order Traversal
- Word Ladder
- Word Ladder II
- Remove Invalid Parentheses
- Shortest Distance from All Buildings
- Minesweeper
- Sliding Puzzle
- Bus Routes
- K-Similar Strings
- Shortest Path to Get All Keys
- Shortest Path in Binary Matrix
- Minimum Moves to Reach Target with Rotations
- Minimum Moves to Move a Box to Their Target Location
- Shortest Path in a Grid with Obstacles Elimination
Topological Sort
Topological Sort is used to solve problems like prerequisite, dependency problems.
Video: https://www.youtube.com/watch?v=Q9PIxaNGnig
Some events must occur before others.
Topological sort is ordering of the nodes in a directed graph where for each directed edge from node A to node B, node A appears before node B in the ordering.
The topological algorithm can find a topological ordering in O(V+E) time. The sort ordering are NOT unique.
Set: keep track of visited nodes. If visited, put node in set, explore its children. If all children are in the visited
set, put node into stack.
Stack: sorted. Only when vertices are fully explored(all children visited), put such vertices into stack.
Can also be used to detect cycle in graph.
Only Directed Acyclic Graphs have topological sort. By definition, all trees have topological orders.
[Related Problems]
- School class prerequesites
- Program dependencies
- Event scheduling
- Assembly instructions
Kahn’s Algorithm
https://www.youtube.com/watch?v=cIBFEhD77b4
Repeatedly remove nodes without any dependencies from the graph and add them to the topological ordering. As nodes without dependencies (and their outgoing edges) are removed from the graph, new nodes without dependencies should become free. We repeat removing nodes without dependencies from the graph until all nodes are processed, or a cycle is discovered.
- Begin by counting the incoming degree of each node, store them in an array
- Use a queue to track which node to be processed next
- Return invalid if indegree list has non-zero in the end
207. Course Schedule
Video: Topological solution: https://www.youtube.com/watch?v=M6SBePBMznU
Video: BFS solution: https://www.youtube.com/watch?v=zkTOIVUdW-I
Has two status: visited and visiting, if cur == visiting, means we start from cur and go back to cur again, means has cycle in the graph
[Solution]
- Construct a HashMap key: each class, value: the direct children of the class
- Construct a
indegree list
to keep track of all the node’s indegree - Run BFS: Construct a
queue
, put all node in theindegree list
whose value is 0 - while
queue.size() != 0
pop nodesi
fromqueue
, reduce the indegree of the child ofi
inindegree
list by 1, check the map of their children. If the children’s indegree == 0, put the child into thequeue
- Loop through the
indegree list
, if any node has value != 0, return false
Recursive Solution: 148s1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
# Prepare graph
g = {}
for edge in prerequisites:
if edge[0] not in g:
g[edge[0]] = []
if edge[1] not in g:
g[edge[1]] = [edge[0]]
else:
g[edge[1]].append(edge[0])
visited = []
visiting = []
# print(g)
def dfs(node):
if node in visited:
return True
if node in visiting:
return False
visiting.append(node)
for neighbor in g[node]:
if not dfs(neighbor):
return False
visited.append(node)
visiting.pop()
return True
for node in g:
if not dfs(node): # If any node have cycle
return False
return True
If the question has something like 0 -> n, we can consider using it as index in the array.
Iterative Solution1
2
3
4
5
6
7
8Construct two lists with out and in information of the graph
Start from node whose out degree == 0, bottom up, visit the node and remove it from the graph
[[1,0],[2,0],[1,2],[1,3],[3,0]] [1 <- 0]
out | | prereq
3 |0|
0 |1| 0,2,3
1 |2| 0
1 |3| 0
1 | def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool: |
210. Course Schedule II
Leetcode: https://leetcode.com/problems/course-schedule-ii/
Note:
- Use a stack to store the sequence
- Use two sets, one for visited, one for visiting nodes to detect if there’s loop in the graph
1 | import java.util.HashMap; |
1 | def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]: |
269. Alien Dictionary
Leetcode: https://leetcode.com/problems/alien-dictionary/
- Construct the map first
- Topo sort later
1 | def alienOrder(self, words: List[str]) -> str: |
310. Minimum Height Trees
Leetcode: https://leetcode.com/problems/minimum-height-trees/
- There would be at most 2 trees that satisfy the condition
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37def findMinHeightTrees(self, n: int, edges: List[List[int]]) -> List[int]:
# furtherst distance to other node is minimum
# memo + dfs
# build graph
if n <= 2:
return [i for i in range(n)]
graph = collections.defaultdict(set)
neibCount = [0 for _ in range(n)]
nodes = set([i for i in range(n)])
for u, v in edges:
neibCount[u] += 1
neibCount[v] += 1
graph[u].add(v)
graph[v].add(u)
remainingNodes = n
removed = set()
leaves = []
for i in range(n):
if neibCount[i] == 1:
leaves.append(i)
remain = n
while remain > 2:
newLeaves = []
remain -= len(leaves)
while leaves:
leaf = leaves.pop()
for neib in graph[leaf]:
graph[neib].remove(leaf)
neibCount[neib] -= 1
if neibCount[neib] == 1:
newLeaves.append(neib)
leaves = newLeaves
return leaves
490. The Maze
Leetcode: https://leetcode.com/problems/the-maze/
[Solution]
- Model the maze into a graph, white cells as nodes, and adjacent white cells as edges
1091. Shortest Path in Binary Matrix
Leetcode: https://leetcode.com/problems/shortest-path-in-binary-matrix/
1 | def shortestPathBinaryMatrix(self, grid: List[List[int]]) -> int: |
DFS
1042. Flower Planting With No Adjacent
(four color problem)
Leetcode: https://leetcode.com/contest/weekly-contest-136/problems/flower-planting-with-no-adjacent/
Video: https://www.youtube.com/watch?v=052VkKhIaQ4
1 | def gardenNoAdj(self, N: int, paths: List[List[int]]) -> List[int]: |
323. Number of Connected Components in an Undirected Graph
Leetcode: https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph/
1 | def countComponents(self, n: int, edges: List[List[int]]) -> int: |
200. Number of Islands
Leetcode: https://leetcode.com/problems/number-of-islands/
1 | def numIslands(self, grid: List[List[str]]) -> int: |
547. Friend Circles
Leetcode: https://leetcode.com/problems/friend-circles/
Find the lower land problem
277. Find the Celebrity
Leetcode: https://leetcode.com/problems/find-the-celebrity/
1 | def findCelebrity(self, n): |
997. Find the Town Judge
Leetcode: https://leetcode.com/problems/find-the-town-judge/
Same as above.
1 | def findJudge(self, N, trust): |
Solution 2:
The point with in-degree - out-degree = N - 1
become the judge.
1 | def findJudge(self, N, trust): |
1197. Minimum Knight Moves
Leetcode: https://leetcode.com/problems/minimum-knight-moves/