MHT
[先说有向图,再说无向图]
leetcode有三道题用到topological sort: course schedule I/II, minimum height tree(MHT)。course schedule是directed graph而MHT是undirected graph。
Course Schedule
- input: 边的List,因为要bfs/dfs的过程要沿着每一个结点的neighbors populate,所以要转化为adjacent matrix或者adjacent list的表示
- output: I是判断是否可以topological sort(即graph没有环),II要求输出排序的课程
- dfs的方法
- idea:每一条dfs的路径都是一段partial order,两个目标:构建多有partial order的路径,判断是否有环
- curRec:当前的partial order路径,res:结果队列,根据topological order,最底层排在头,所以当前node在dfs recursion之后近结果队列
- 环的判断:对于directed graph,不能用visited来判断环,比如下图的例子。visited数组的作用是排除多余的dfs搜索。环只能发生在同一dfs搜索路径下,所以通过curRec set来track。同时function的return会populate back到顶层
- 搜索的起点可能是一条完整连通路径的任何一点,从这点开始,可以覆盖到底,因此路径上的其他node都是在topological sequence靠后的位置,所以在结果里也是后入q的。同时由于visited数组,可以排除重复进res的情况
- bfs的方法
- 基本:用q来maintain层级,最终q中元素的顺序就是排序顺序
- indegree数组来保存每个结点当前的入度,初始可以通过遍历adjacent list得到
- 从所有入度为0的结点开始,如果其neighbor的入度-1==0,说明是下一层的结点,入q。这样一层层遍历直到没有下一层产生。
- loop invariant:只需要排序不需要结果返回最后一层的结点,可以用!q.isEmpty(),而每个iteration只出队列一个结点。如果已知当前为无环图,也可以存一个待处理node的set: nodes,当neighbor进q后从nodes里去掉
MHT
对于undirected graph,更新indegree要同时更新边的两个结点,indegree为1即为leaf。注意如果是孤立结点,入度可以为0,所以初始化的检测条件是indegree<=1
因为要返回树的根(可能是一个也可能是两个),即bfs的最后一层,需要用逐层的方式做bfs,这里用到两个q:q:全是indegree<=1的, bfs当前层,qnext: bfs的下一层
class Solution(object):
def findMinHeightTrees(self, n, edges):
"""
:type n: int
:type edges: List[List[int]]
:rtype: List[int]
"""
adjList = [set() for i in range(n)]
for e in edges:
adjList[e[0]].add(e[1])
adjList[e[1]].add(e[0])
q = []
for i in range(len(adjList)):
if len(adjList[i])==1 or len(adjList[i])==0:
q.append(i)
while q:
qnext = []
for i in range(len(q)):
for e in adjList[q[i]]:
adjList[e].remove(q[i])
if len(adjList[e])==1:
qnext.append(e)
if not qnext: return q
q=qnext
return []