
上篇我们介绍了BFS解决拓扑排序的背景知识,本篇我们将结合具体题目分析,进一步深化对于该算法的理解运用。
该题为一个明显的拓扑排序问题,根据上篇讲解,我们可以这样子处理
class Solution {
public:
bool canFinish(int n, vector<vector<int>>& prerequisites) {
unordered_map<int,vector<int>> edges;//邻接表
vector<int> in(n);//入度
//建图
for(auto e: prerequisites)
{
int a=e[0],b=e[1];
edges[b].push_back(a);
in[a]++;
}
queue<int> q;
//将入度为0的节点入队列
for(int i=0;i<n;i++)
{
if(in[i]==0)
{
q.push(i);
}
}
//层序遍历
while(q.size())
{
int t=q.front();
q.pop();
for(int e : edges[t])
{
in[e]--;
if(in[e]==0)
{
q.push(e);
}
}
}
for(int i=0;i<n;i++)
{
if(in[i])
{
return false;
}//说明无法学完所有课程
}
return true;
}
};该题与上题要求基本相同,只是返回值要求返回可能的一种学习顺序,如果不存在,则返回空数组
判断是否可以学习的思路与上题相同,我们只需要在层序遍历时,用一个数组记录当前学习顺序即可。
class Solution {
public:
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
unordered_map<int,vector<int>> edges;//邻接表
vector<int> in(numCourses);//入度
vector<int> ret;//返回值
vector<int> temp;//空数组
queue<int> q;
//建图
for(auto e:prerequisites)
{
int a=e[0],b=e[1];
edges[b].push_back(a);
in[a]++;
}
//入度为0的节点入队列
for(int i=0;i<numCourses;i++)
{
if(in[i]==0)
{
q.push(i);
}
}
while(q.size())
{
int t=q.front();
q.pop();
ret.push_back(t);//更新结果
for(int e:edges[t])
{
in[e]--;
if(in[e]==0)
{
q.push(e);
}
}
}
for(int i=0;i<numCourses;i++)
{
if(in[i])
{
return temp;
}
}//存在未完成情况,返回空数组
return ret;
}
};题目要求一时间难以读懂,我们来简单翻译一下:
假设 words = [“wrt”,“wrf”,“er”,“ett”,“rftt”],我们可以得到字母之间的一些依赖关系:
最终需要返回题目中外星词典的递增顺序,若不存在合法的顺序,则返回空
我们通过比较相邻的单词,找出它们的第一个不同字母。这些字母的顺序关系就可以帮助我们构建字母的顺序图。
图的构建:
拓扑排序:
class Solution {
public:
unordered_map<char,unordered_set<char>> edges;//边
unordered_map<char,int> in;//入度
bool check;//处理特殊情况
void add(string& s1,string& s2)
{
int n=min(s1.size(),s2.size());
int i;
for( i=0;i<n;i++)
{
if(s1[i]!=s2[i])
{
char a=s1[i],b=s2[i];
if(!edges.count(a) || !edges[a].count(b))//如果之前为记录过,则记录这条边a->b
{
edges[a].insert(b);
in[b]++;//更新边和入度节点
}
break;//注意跳出循环
}
}
if(i==s2.size()&&i<s1.size())//处理abc ab这种特殊情况
{
check=true;
}
}
string alienOrder(vector<string>& words) {
//建图和初始化
for(auto e: words)
{
for(auto ch:e)
{
in[ch]=0;
}//将所有字符的入度都初始化为0
}
int n=words.size();
for(int i=0;i<n;i++)
{
for(int j=i+1;j<n;j++)
{
add(words[i],words[j]);
if(check)
{
return "";//存在非法情况
}
}
}
//拓扑排序
queue<char> q;
string ret;
//将所有入度为0的节点
for(auto [a,b] :in)
{
if(b==0)
{
q.push(a);
}
}
while(q.size())
{
char t=q.front();
q.pop();
ret+=t;
for(auto e:edges[t])
{
if(--in[e]==0) q.push(e);
}
}
for(auto [a,b] :in)
{
if(b!=0)
{
return "";
}
}//判断是否存在不合法顺序
return ret;
}
};本篇关于BFS解决拓扑排序的讲解就暂告段落啦,希望能对大家的学习产生帮助,欢迎各位佬前来支持斧正!!!