【图】Leetcode 797,207 ,210排课表问题 ,三种方法遍历,拓扑排序,回溯解决课程表问题

本文详细介绍了图的基础知识,包括图的两种数据结构、LeetCode中图的构造方法以及图的遍历方法。结合LeetCode题目207和210,探讨了图遍历和拓扑排序在解决课程表问题中的应用,并提供了解题策略。此外,还讲解了如何使用图遍历和回溯算法解决LeetCode 797题目的所有可能路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

此篇文章讲解了图的两种数据结构,怎样构造图,和图遍历的模板。

由此引出leetcode 797所有可能通路 ,leetcode 207 课程表 ,leetcode 210 课程表II的解答。

解决了图问题中常出现:DFS遍历图,回溯法遍历图,环检测,拓扑排序的问题。

目录

一、 图的基础

(1)图有两种数据结构构成。

(2)leetcode中图常用的构造方法 

(3)图的遍历方法

 二、leetcode 207 课程表

三、3种方法解答 Leetcode 210 课程表II

方法1)图遍历

方法2) 拓扑排序

四、图的遍历和回溯两种方法解决 leetcode 797 所有可能的路径

1)图的遍历解法

2)回溯算法解法


一、 图的基础

(1)图有两种数据结构构成。

1)邻接矩阵 :即用V-V矩阵来代表每个顶点和边,V代表顶点。如果是无加权图则用简单的二维布尔数组表示。加权图则可以用二维数组来表示边的距离。它的好处是访问很快,缺点是费空间。如果图有很多顶点但是边不多,则造成不必要的空间损失。这时候,接邻列表就很有优势了。

 

2)接邻列表:每个顶点接一个列表,代表相邻的顶点。这样空间使用就从上一个表示方法 V * V

降到了 V + E. 每次添加边,提供了固定的时间。 同时节约了空间。

(2)leetcode中图常用的构造方法 

leetcode中使用邻接表的构图比较多,以下是建立图的函数。

List<Integer>[] buildGraph(int numVertex, int[][] edges){
  List<Integer>[] graph = new LinkedList[numCourses];
  for(int[] edge : edges){
  int from = edge[0];
  int to = edge[1];
  graph[from].add(to);
}

(3)图的遍历方法

图的数据结构就是多叉树的延伸,多叉树就是二叉树的延伸,二叉树就是链表的延伸。我们二叉树的数据结构中也有两种:一是用数组表示的堆,二是更加常见的用列表表示的树。因为leetcode中更加常出现的结构是邻接列表,也就是底层数据结构是列表。所以与二叉树的遍历存在着非常高的相似性。我们一起来看一下。

二叉树的遍历:

class TreeNode{
int val;
TreeNode leftchild;
TreeNode rightchild;
}

traverse(TreeNode root){
   if(root == null) return;
   //前序遍历
   traverse(root.leftchild);
   //中序遍历
   traverse(root.rightchild);
   //后序遍历
}

与多叉树的遍历十分的类似。多叉树的遍历框架:

class TreeNode{
int val;
TreeNode[] children;
}

traverse(TreeNode root){
   if(root == null) return;
   for(TreeNode node : children){
   traverse(node);
   }
}

图和多叉树不同之处在于,图可能有环的。你从图的一个节点开始遍历,很可能又会到这个节点。所以我们会加入visit[] 数组来避免你走回头路:

class Vertex{
int val;
Vertex[] neighbours;}

void traverse(Graph g, Vertex s){
if(visit[s]) return
// 将当前节点 s 标记为已经遍历
visit[s] = true;
for(Vertex v : g.neighbours(s)){
   traverse(g, v)
}

}

那有些图不是所有的节点都是相连怎么办呢?加一个for循环将所有节点都作为起点都调用一下traverse()函数就可以了。如下图:

class Vertex{
int val;
Vertex[] neighbours;}

void traverseAllGraph(Graph g, int v){
    visited = new boolean[v];
    for(int i=0; i< v; i++){
       traverse(g,i);
    }
}

void traverse(Graph g, Vertex s){
if(visit[s]) return
// 将当前节点 s 标记为已经遍历
visit[s] = true;
for(Vertex v : g.neighbours(s)){
   traverse(g, v)
}

}

我想

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值