图基础:
- 定义:描述事物之间的关系。
- 包括:节点集V={V1,V2......,Vn},边集合E={e1,e2,......,em},其中ei=(vi,vi‘)
- G=<V,E>
- 包括有向图和无向图
- 空间复杂度一般为:O(n+m)或O(n2)
- 主要应用包括:邻接矩阵,邻接表
图的存储结构:
1、邻接矩阵表示法:
如果 第 1个点和第 3个点 相连则 matrix[0][2]=1;如果两节点之间有一条弧,则邻接矩阵中对应的元素为1;否则为0。可以看出,这种表示法非常简单、直接。但是,在邻接矩阵的所有n*n 个元素中,只有 m个为非零元。如果网络比较稀疏,这种表示法浪费大量的存储空间,从而增加了在网络中查找弧的时间。
2、邻接表表示法:
邻接表表示法将图以邻接表(adjacency lists)的形式存储在计算机中。所谓图的邻接表,也就是图的所有节点的邻接表的集合;而对每个节点,它的邻接表就是它的所有出弧。邻接表表示法就是对图的每个节点,用一个单向链表列出从该节点出发的所有弧,链表中每个单元对应于一条出弧。为了记录弧上的权,链表中每个单元除列出弧的另一个端点外,还可以包含弧上的权等作为数据域。图的整个邻接表可以用一个指针数组表示。 - 举例:
拓扑排序基础:
- 定义:有向无环图(DAG)
- 场景:任务依赖
- 时间复杂度O(n+m),附加空间复杂度O(n)
- 每次找入度为0的点(入度就是没有指向它的箭头)
- 维护入度
- 过程:
- 应用:假设你有一些任务,以及这些任务之间的任务依赖,每次任务有一个完成时间,假设可以无限并行,最少要多少时间才能完成?
leetcode例题:参考
现在你总共有 n 门课需要选,记为 0
到 n-1
。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]
给定课程总量以及它们的先决条件,判断是否可能完成所有课程的学习?
示例 1:
输入: 2, [[1,0]]
输出: true
解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。
示例 2:
输入: 2, [[1,0],[0,1]]
输出: false
解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。
说明:
- 输入的先决条件是由边缘列表表示的图形,而不是邻接矩阵。详情请参见图的表示法。
- 你可以假定输入的先决条件中没有重复的边。
提示:
- 这个问题相当于查找一个循环是否存在于有向图中。如果存在循环,则不存在拓扑排序,因此不可能选取所有课程进行学习。
- 通过 DFS 进行拓扑排序 - 一个关于Coursera的精彩视频教程(21分钟),介绍拓扑排序的基本概念。
-
拓扑排序也可以通过 BFS 完成。
class Solution:
def canFinish(self, numCourses, prerequisites):
"""
:type numCourses: int
:type prerequisites: List[List[int]]
:rtype: bool
"""
graph = collections.defaultdict(list)
indegrees = collections.defaultdict(int)
for u, v in prerequisites:
graph[v].append(u)
indegrees[u] += 1
for i in range(numCourses):
zeroDegree = False
for j in range(numCourses):
if indegrees[j] == 0:
zeroDegree = True
break
if not zeroDegree: return False
indegrees[j] = -1
for node in graph[j]:
indegrees[node] -= 1
return True
最短路基础:
- 定义:假设E集合(边集)是有权重的
- 具象:V集合代表城市,E集合代表城市间高速路,权重为高速路长度,两点间存在若干条通路,长度最短的通路即最短路
单元最短路(Dijkstra):
- 定义:给定起点s,求到任意点的最短路
- 贪心:每次找最近的点
- 维护s到每个点的距离
- 局部最优等于全局最优
- 时间复杂度O(n2),附加空间复杂度O(n)
- 算法:
- SPFA(Bellman-Ford)算法:参考
单源次短路:
- 给定起点s,求到任意点的次短路(距离大于最短路的最短的路)
- v的次短路:顶点u的最短路再加上u->v的边,顶点u的次短路再加上u->v的边
- 在原来的代码上加入次短路即可
任意两点最短路(Floyed):
- 求到任两点间的最短路
- 类似动态规划:每次加入一个点
- 维护任意两点间的距离
- 时间复杂度O(n3),附加空间复杂度O(n2)
- 算法:
最小生成树(Prim):
- 定义:无向图
- 树-> 无环(圈)
- 破圈法,避圈法
- 时间复杂度O(n^2)
To be continue......