第十一章:图论part01
图论理论基础
大家可以在看图论理论基础的时候,很多内容 看不懂,例如也不知道 看完之后 还是不知道 邻接矩阵,邻接表怎么用, 别着急。
理论基础大家先对各个概念有个印象就好,后面在刷题的过程中,每个知识点都会得到巩固。
www.programmercarl.com/kamacoder/%… 在 JavaScript 中,我们可以用两种方式来构建图的数据结构:
- 邻接表:使用数组或对象来表示节点的连接,适合稀疏图。
- 邻接矩阵:用二维数组来表示节点之间的边权重,适合稠密图。
邻接表构建
邻接表适合用于 稀疏图(即节点多但边少的图)。每个节点拥有一个数组,数组中的每个元素表示该节点连接的其他节点,以及对应的边权重。
/**
* 构建邻接表
* @param {number} n - 节点数量
* @param {number[][]} edges - 每条边的起点、终点、权重
* @returns {Array} - 邻接表
*/
function buildAdjList(n, edges) {
const adjList = Array.from({ length: n }, () => []);
edges.forEach(([from, to, weight]) => {
adjList[from].push([to, weight]);
adjList[to].push([from, weight]); // 无向图
});
return adjList;
}
// 示例使用
const n = 5;
const edges = [
[0, 1, 4],
[0, 2, 3],
[1, 2, 1],
[1, 3, 2],
[2, 4, 5]
];
const adjList = buildAdjList(n, edges);
console.log(adjList);
邻接矩阵构建
邻接矩阵适合用于 稠密图(即边的数量接近节点数量的平方)。矩阵中 matrix[i][j] 的值表示节点 i 到 j 的边权重。
/**
* 构建邻接矩阵
* @param {number} n - 节点数量
* @param {number[][]} edges - 每条边的起点、终点、权重
* @returns {Array} - 邻接矩阵
*/
function buildAdjMatrix(n, edges) {
const adjMatrix = Array.from({ length: n }, () => Array(n).fill(Infinity));
edges.forEach(([from, to, weight]) => {
adjMatrix[from][to] = weight;
adjMatrix[to][from] = weight; // 无向图
});
return adjMatrix;
}
// 示例使用
const adjMatrix = buildAdjMatrix(n, edges);
console.log(adjMatrix);
两种方法的适用场景
- 邻接表:更适合稀疏图,占用空间较少,且能够快速查找特定节点的邻居。
- 邻接矩阵:适合稠密图,可以快速判断两个节点之间是否存在边,但空间复杂度较高。
深搜理论基础
了解一下深搜的原理和过程
www.programmercarl.com/kamacoder/%…
98. 所有可达路径
www.programmercarl.com/kamacoder/0…
是的,graph[i] 表示的是从节点 i 可以直接访问的所有节点。也就是说,graph[i] 是一个数组,包含了所有与节点 i 直接相连的节点列表。如果从 i 节点到 graph[i][j] 节点存在一条有向边,那么 graph[i][j] 就在这个数组中。
例子:
假设有这样一个图:
0 → 1 → 3
↓
2 → 3
其对应的邻接列表表示为:
let graph = [
[1, 2], // 节点0可以到达节点1和节点2
[3], // 节点1可以到达节点3
[3], // 节点2可以到达节点3
[] // 节点3没有指向任何节点
];
在这种表示方式中,graph[i] 列表中的每个元素 graph[i][j] 表示存在一条从节点 i 到节点 graph[i][j] 的有向边。
解释:
- 对于节点
0,graph[0] = [1, 2]表示从节点0有两条边分别指向节点1和节点2。 - 对于节点
1,graph[1] = [3]表示从节点1有一条边指向节点3。 - 对于节点
2,graph[2] = [3]表示从节点2有一条边指向节点3。 - 节点
3没有指向任何其他节点,因此graph[3] = []。
用这种方式进行 DFS:
根据这个表示法,我们可以通过 DFS 递归遍历所有从起点 0 到终点 n-1 的路径:
/**
* @param {number[][]} graph
* @return {number[][]}
*/
var allPathsSourceTarget = function(graph) {
let res = [];
let path = [0]; // 起始路径
function dfs(cur, n) {
if (cur === n) {
res.push([...path]); // 到达目标节点,保存路径
return;
}
// 遍历当前节点的所有相邻节点
for (let next of graph[cur]) {
path.push(next); // 进入下一个节点
dfs(next, n); // 深度优先搜索
path.pop(); // 回溯
}
}
dfs(0, graph.length - 1); // 从节点0开始搜索
return res;
};
运行:
let graph = [[1,2], [3], [3], []];
console.log(allPathsSourceTarget(graph));
// 输出: [[0,1,3], [0,2,3]]
这个方法有效地找到所有从起点到终点的路径。