1.所有可能的路径
题目要求:
给你一个有 n 个节点的 有向无环图(DAG),请你找出所有从节点 0 到节点 n-1 的路径并输出(不要求按特定顺序)
graph[i] 是一个从节点 i 可以访问的所有节点的列表(即从节点 i 到节点 graph[i][j]存在一条有向边)。
示例 1:

输入:graph = [[1,2],[3],[3],[]]
输出:[[0,1,3],[0,2,3]]
解释:有两条路径 0 -> 1 -> 3 和 0 -> 2 -> 3
难度:🌟🌟
解答:图的遍历框架
// 记录被遍历过的节点
boolean[] visited;
// 记录从起点到当前节点的路径
boolean[] onPath;
/* 图遍历框架 */
void traverse(Graph graph, int s) {
if (visited[s]) return;
// 经过节点 s,标记为已遍历
visited[s] = true;
// 做选择:标记节点 s 在路径上
onPath[s] = true;
for (int neighbor : graph.neighbors(s)) {
traverse(graph, neighbor);
}
// 撤销选择:节点 s 离开路径
onPath[s] = false;
}
class Solution {
List<List<Integer>> res = new LinkedList();
public List<List<Integer>> allPathsSourceTarget(int[][] graph) {
LinkedList<Integer> path = new LinkedList();
traverse(graph, 0, path);
return res;
}
public void traverse(int[][] graph, int s, LinkedList<Integer> path){
path.add(s);
int n =graph.length;
if(s == n-1){ //到达终点 记录路径 结束
res.add(new LinkedList<>(path));
}
for(int v:graph[s]){ //遍历相邻节点
traverse(graph,v,path);
}
//s不能到达终点
path.removeLast();
return;
}
}
2.课程表
题目要求:
你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。
在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。
例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。
请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。
示例 1:
输入:numCourses = 2, prerequisites = [[1,0]]
输出:true
解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。
难度:🌟🌟
解答:
构造图+环检测 // 记录一次递归堆栈中的节点 boolean[] onPath;
// 记录遍历过的节点,防止走回头路 boolean[] visited;
class Solution {
// 记录一次递归堆栈中的节点
boolean[] onPath;
// 记录遍历过的节点,防止走回头路
boolean[] visited;
// 记录图中是否有环
boolean hasCycle = false;
public boolean canFinish(int numCourses, int[][] prerequisites) {
List<Integer>[] graph = buildGraph(numCourses, prerequisites);
visited = new boolean[numCourses];
onPath = new boolean[numCourses];
for (int i = 0; i < numCourses; i++) {
// 遍历图中的所有节点
traverse(graph, i);
}
// 只要没有循环依赖可以完成所有课程
return !hasCycle;
}
public List<Integer>[] buildGraph(int numCourses, int[][] prerequisites){
List<Integer>[] graph = new LinkedList[numCourses];
// 图中共有 numCourses 个节点
for (int i=0;i<numCourses;i++){
graph[i] = new LinkedList<>();
}
for (int edge[]:prerequisites){
int from = edge[1];
int to = edge[0];
graph[from].add(to);
}
return graph;
}
public void traverse(List<Integer>[] graph, int s){
if(onPath[s]){
hasCycle = true; //本次路径出现环
}
if(visited[s] || hasCycle){
// 如果已经找到了环,也不用再遍历了
return;
}
visited[s] = true;
onPath[s] = true;
for (int t:graph[s]) {
traverse(graph,t);
}
onPath[s] = false;
}
}
拓扑排序 将后序遍历的结果进行反转,就是拓扑排序的结果。
3.可能的二分法 二分图 双色问题
题目要求:
给定一组 n 人(编号为 1, 2, ..., n), 我们想把每个人分进任意大小的两组。每个人都可能不喜欢其他人,那么他们不应该属于同一组。
给定整数 n 和数组 dislikes ,其中 dislikes[i] = [ai, bi] ,表示不允许将编号为 ai 和 bi的人归入同一组。当可以用这种方法将所有人分进两组时,返回 true;否则返回 false。
示例 1:
输入:n = 4, dislikes = [[1,2],[1,3],[2,4]]
输出:true
解释:group1 [1,4], group2 [2,3]
难度:🌟🌟
解答:
互相讨厌的关系看左边---- 构建无向图
相邻节点不同组----染双色色----遍历
private boolean ok = true;
private boolean[] color;
private boolean[] visited;
public boolean possibleBipartition(int n, int[][] dislikes) {
// 图节点编号从 1 开始
color = new boolean[n + 1];
visited = new boolean[n + 1];
// 转化成邻接表表示图结构
List<Integer>[] graph = buildGraph(n, dislikes);
for (int v = 1; v <= n; v++) {
if (!visited[v]) {
traverse(graph, v);
}
}
return ok;
}
// 和之前的 traverse 函数完全相同
private void traverse(List<Integer>[] graph, int v){
if (!ok) {
return;
}
visited[v] = true;
for (int current : graph[v]){
if(!visited[current]){ //没遍历过
color[current]=!color[v]; //反响染色
traverse(graph,current);
}else {
if (color[current] == color[v]){
ok = false;
return;
}
}
}
return;
}
// 建图函数
private List<Integer>[] buildGraph(int n, int[][] dislikes){
List<Integer>[] graph = new LinkedList[n+1];
for (int i = 1; i <= n; i++) {
graph[i] = new LinkedList<>();
}
for (int[] edge:dislikes) {
int w = edge[0];
int m = edge[1];
//无向图」相当于「双向图」
graph[w].add(m);
graph[m].add(w);
}
return graph;
}
4.网络延迟时间 Dijkstra
题目要求:
有 n 个网络节点,标记为 1 到 n。
给你一个列表 times,表示信号经过 有向 边的传递时间。 times[i] = (ui, vi, wi),其中 ui 是源节点,vi 是目标节点, wi 是一个信号从源节点传递到目标节点的时间。
现在,从某个节点 K 发出一个信号。需要多久才能使所有节点都收到信号?如果不能使所有节点收到信号,返回 -1 。
示例 1:

输入:times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
输出:2
难度:🌟🌟
解答: