
Breadth-First Search (BFS) 在拓扑排序中的应用主要是用来解决有向无环图(DAG)的拓扑排序问题。拓扑排序是对有向图中所有节点的一种线性排序,使得对于每一条有向边 (u, v),节点 u 在排序中都出现在节点 v 的前面。如果图中存在环路,则无法进行拓扑排序。
BFS 解决拓扑排序的步骤如下:
如果最终遍历过的节点数等于图中的节点数,说明图是有向无环图,可以得到一个拓扑排序。
题目链接:https://leetcode.cn/problems/course-schedule/
你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。
在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。
请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。
示例 1:
输入:numCourses = 2, prerequisites = [[1,0]] 输出:true 解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。
示例 2:
输入:numCourses = 2, prerequisites = [[1,0],[0,1]] 输出:false 解释:总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。
提示:
思路
这里我们可以采用容器模拟邻接矩阵或者邻接表来进行拓扑排序,判断这个图是否有环的方式来解决这个问题
代码
class Solution {
public:
bool canFinish(int numCourses, vector>& prerequisites) {
unordered_map> edges;
vector in(numCourses,0);
for(vector& e:prerequisites){
int a=e[0],b=e[1];
edges[b].push_back(a);
in[a]++;
}
queue q;
for(int i=0;i
int t=q.front();
q.pop();
for(int e:edges[t]){
in[e]--;
if(in[e]==0) q.push(e);
}
}
for(int i:in) if(i) return false;
return true;
}
};
题目链接:https://leetcode.cn/problems/course-schedule-ii/
现在你总共有 numCourses 门课需要选,记为 0 到 numCourses - 1。给你一个数组 prerequisites ,其中 prerequisites[i] = [ai, bi] ,表示在选修课程 ai 前 必须 先选修 bi 。
返回你为了学完所有课程所安排的学习顺序。可能会有多个正确的顺序,你只要返回 任意一种 就可以了。如果不可能完成所有课程,返回 一个空数组 。
示例 1:
输入:numCourses = 2, prerequisites = [[1,0]] 输出:[0,1] 解释:总共有 2 门课程。要学习课程 1,你需要先完成课程 0。因此,正确的课程顺序为 [0,1] 。
示例 2:
输入:numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]] 输出:[0,2,1,3] 解释:总共有 4 门课程。要学习课程 3,你应该先完成课程 1 和课程 2。并且课程 1 和课程 2 都应该排在课程 0 之后。 因此,一个正确的课程顺序是 [0,1,2,3] 。另一个正确的排序是 [0,2,1,3] 。
示例 3:
输入:numCourses = 1, prerequisites = [] 输出:[0]
思路
总体思路和上面一致,我们只需要在每次将入度为0的点顺序保存即为拓扑排序的顺序。
代码
class Solution {
public:
vector findOrder(int numCourses, vector>& prerequisites) {
unordered_map> edges;
vector in(numCourses,0);
for(vector& e:prerequisites){
int a=e[0],b=e[1];
edges[b].push_back(a);
in[a]++;
}
queue q;
vector ret;
for(int i=0;i
q.push(i);
ret.push_back(i);
}
while(!q.empty()){
int t=q.front();
q.pop();
for(int e:edges[t]){
in[e]--;
if(in[e]==0){
q.push(e);
ret.push_back(e);
}
}
}
for(int i:in) if(i) return {};
return ret;
}
};
题目链接:https://leetcode.cn/problems/Jf1JuT
现有一种使用英语字母的外星文语言,这门语言的字母顺序与英语顺序不同。
给定一个字符串列表 words ,作为这门语言的词典,words 中的字符串已经 按这门新语言的字母顺序进行了排序 。
请你根据该词典还原出此语言中已知的字母顺序,并 按字母递增顺序 排列。若不存在合法字母顺序,返回 "" 。若存在多种可能的合法字母顺序,返回其中 任意一种 顺序即可。
字符串 s 字典顺序小于 字符串 t 有两种情况:
示例 1:
输入:words = ["wrt","wrf","er","ett","rftt"] 输出:"wertf"
示例 2:
输入:words = ["z","x"] 输出:"zx"
示例 3:
输入:words = ["z","x","z"] 输出:"" 解释:不存在合法字母顺序,因此返回 "" 。
提示:
思路
将题意搞清楚之后,这道题就变成了判断有向图时候有环,可以用拓扑排序解决。
如何搜集信息(如何建图):
a. 两层for循环枚举出所有的两个字符串的组合;
b. 然后利用指针,根据字典序规则找出信息。
代码
class Solution {
unordered_map> edges;
unordered_map in;
bool cheak=false;
void add(string& s1,string& s2){
int n=min(s1.size(),s2.size());
int i=0;
while(i
if(s1[i]!=s2[i]){
char a=s1[i],b=s2[i];
if(!edges.count(a)||!edges[a].count(b)){
edges[a].insert(b);
in[b]++;
}
break;
}
i++;
}
if(i==s2.size()&&i& words) {
for(auto& s:words)
for(auto& ch:s)
in[ch]=0;
int n=words.size();
for(int i=0;i
add(words[i],words[j]);
if(cheak) return "";
}
queue q;
for(auto& [a,b]:in)
if(b==0) q.push(a);
string ret;
while(!q.empty()){
char t=q.front();
q.pop();
ret+=t;
for(char ch:edges[t])
if(--in[ch]==0) q.push(ch);
}
for(auto& [a,b]:in) if(b) return "";
return ret;
}
};
上一篇:数据结构(二)基本概念和术语