These are the 3 LeetCode problems pertinent to DAG, graph via bfs. The problem “Course Schedule II” pertains to “Topological sorting”, which is more like a way of traversing nodes from my perspective. Problem “Minimum Height Tree” relates to the concept of graph as a superset of trees. Also, how in-degrees of graph nodes are expressed as heights of tree nodes is ausgezeichnet as well.

207. Course Schedule

There are a total of n courses you have to take, labeled from 0 to n-1.

Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]

Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?

Example 1:

1
2
3
4
Input: 2, [[1,0]] 
Output: true
Explanation: There are a total of 2 courses to take.
To take course 1 you should have finished course 0. So it is possible.

Example 2:

1
2
3
4
5
Input: 2, [[1,0],[0,1]]
Output: false
Explanation: There are a total of 2 courses to take.
To take course 1 you should have finished course 0, and to take course 0 you should
also have finished course 1. So it is impossible.

Note:

  1. The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
  2. You may assume that there are no duplicate edges in the input prerequisites.

Many hints:

  1. This problem is equivalent to finding if a cycle exists in a directed graph. If a cycle exists, no topological ordering exists and therefore it will be impossible to take all courses.
  2. Topological Sort via DFS - A great video tutorial (21 minutes) on Coursera explaining the basic concepts of Topological Sort.
  3. Topological sort could also be done via BFS.
Solution

Actually, I did it via bfs which looks much easier to me.

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
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<vector<int>> graph(numCourses, vector<int>());
vector<int> in(numCourses);
for (auto a : prerequisites) {
graph[a[1]].push_back(a[0]);
++in[a[0]];
}
queue<int> q;
for (int i = 0; i < numCourses; ++i) {
if (in[i] == 0) q.push(i);
}
while (!q.empty()) {
int t = q.front(); q.pop();
for (int i : graph[t]) {
--in[i];
if (in[i] == 0) q.push(i);
}
}
for (int i = 0; i < numCourses; ++i) {
if (in[i] != 0) return false;
}
return true;
}
};

210. Course Schedule II

Similar. Problem link.

Solution

Topological sorting: to me, it’s more like a traversal than a sorting.

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
class Solution {
public:
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
vector<int> res;
vector<vector<int>> graph(numCourses, vector<int>());
vector<int> in(numCourses);
for (auto a : prerequisites) {
graph[a[1]].push_back(a[0]);
++in[a[0]];
}
queue<int> q;
for (int i = 0; i < numCourses; ++i) {
if (in[i] == 0) q.push(i);
}
while (!q.empty()) {
int t = q.front(); q.pop();
res.push_back(t);
for (int i : graph[t]) {
--in[i];
if (in[i] == 0) q.push(i);
}
}
return (res.size() == numCourses) ? res : vector<int>();
}
};

310. Minimum Height Trees

For an undirected graph with tree characteristics, we can choose any node as the root. The result graph is then a rooted tree. Among all possible rooted trees, those with minimum height are called minimum height trees (MHTs). Given such a graph, write a function to find all the MHTs and return a list of their root labels.

Format
The graph contains n nodes which are labeled from 0 to n - 1. You will be given the number n and a list of undirected edges (each edge is a pair of labels).

You can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges.

Example 1:

1
2
3
4
5
6
7
8
9
Input: n = 4, edges = [[1, 0], [1, 2], [1, 3]]

0
|
1
/ \
2 3

Output: [1]

Example 2:

1
2
3
4
5
6
7
8
9
10
11
Input: n = 6, edges = [[0, 3], [1, 3], [2, 3], [4, 3], [5, 4]]

0 1 2
\ | /
3
|
4
|
5

Output: [3, 4]

Note:

According to the definition of tree on Wikipedia): “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.”
The height of a rooted tree is the number of edges on the longest downward path between the root and a leaf.

Solution:

My thoughts:

  1. When building an undirected graph, it’s actually treated as a bi-directional graph. 0->2. When it’s a DG, it’s 1. Interesting.
  2. use unordered_set, not vector, because erase in vector can only erase by parameter index, not element.
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
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
if (n == 1) return {0};
vector<int> res;
vector<unordered_set<int>> graph(n);
queue<int> q;
for (auto e : edges) {
graph[e[0]].insert(e[1]);
graph[e[1]].insert(e[0]);
}
for (int i = 0; i < n; ++i) {
if (graph[i].size() == 1) q.push(i);
}
while (n > 2) {
int size = q.size();
n -= size;
for (int i = 0; i < size; ++i) {
int t = q.front(); q.pop();
for (int j : graph[t]) {
graph[j].erase(t);
if (graph[j].size() == 1) q.push(j);
}
}
}
while (!q.empty()) {
res.push_back(q.front()); q.pop();
}
return res;
}
};