赞
踩
BFS 解决拓扑排序的步骤如下:
如果最终遍历过的节点数等于图中的节点数,说明图是有向无环图,可以得到一个拓扑排序。
题目链接:https://leetcode.cn/problems/course-schedule/
你这个学期必须选修 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 。这是可能的。
示例 2:
输入:numCourses = 2, prerequisites = [[1,0],[0,1]]
输出:false
解释:总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。
提示:
1 <= numCourses <= 2000
0 <= prerequisites.length <= 5000
prerequisites[i].length == 2
0 <= ai, bi < numCourses
prerequisites[i]
中的所有课程对 互不相同思路
这里我们可以采用容器模拟邻接矩阵或者邻接表来进行拓扑排序,判断这个图是否有环的方式来解决这个问题
代码
class Solution { public: bool canFinish(int numCourses, vector<vector<int>>& prerequisites) { unordered_map<int,vector<int>> edges; vector<int> in(numCourses,0); for(vector<int>& e:prerequisites){ int a=e[0],b=e[1]; edges[b].push_back(a); in[a]++; } queue<int> q; for(int i=0;i<numCourses;++i) if(in[i]==0) q.push(i); while(!q.empty()){ 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; } };
edges
存储有向图的边,其中 edges[b]
表示节点 b
指向的所有节点。in
记录每个节点的入度。初始化时,将所有节点的入度设为 0。q
。true
;否则,返回 false
。题目链接:https://leetcode.cn/problems/course-schedule-ii/
现在你总共有 numCourses
门课需要选,记为 0
到 numCourses - 1
。给你一个数组 prerequisites
,其中 prerequisites[i] = [ai, bi]
,表示在选修课程 ai
前 必须 先选修 bi
。
0
,你需要先完成课程 1
,我们用一个匹配来表示:[0,1]
。返回你为了学完所有课程所安排的学习顺序。可能会有多个正确的顺序,你只要返回 任意一种 就可以了。如果不可能完成所有课程,返回 一个空数组 。
示例 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<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) { unordered_map<int,vector<int>> edges; vector<int> in(numCourses,0); for(vector<int>& e:prerequisites){ int a=e[0],b=e[1]; edges[b].push_back(a); in[a]++; } queue<int> q; vector<int> ret; for(int i=0;i<numCourses;++i) if(in[i]==0){ 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; } };
edges
存储有向图的边,其中 edges[b]
表示节点 b
指向的所有节点。in
记录每个节点的入度。初始化时,将所有节点的入度设为 0。q
,同时将这些节点加入结果数组 ret
中。题目链接:https://leetcode.cn/problems/Jf1JuT
现有一种使用英语字母的外星文语言,这门语言的字母顺序与英语顺序不同。
给定一个字符串列表 words
,作为这门语言的词典,words
中的字符串已经 按这门新语言的字母顺序进行了排序 。
请你根据该词典还原出此语言中已知的字母顺序,并 按字母递增顺序 排列。若不存在合法字母顺序,返回 ""
。若存在多种可能的合法字母顺序,返回其中 任意一种 顺序即可。
字符串 s
字典顺序小于 字符串 t
有两种情况:
s
中的字母在这门外星语言的字母顺序中位于 t
中字母之前,那么 s
的字典顺序小于 t
。min(s.length, t.length)
字母都相同,那么 s.length < t.length
时,s
的字典顺序也小于 t
。示例 1:
输入:words = ["wrt","wrf","er","ett","rftt"]
输出:"wertf"
示例 2:
输入:words = ["z","x"]
输出:"zx"
示例 3:
输入:words = ["z","x","z"]
输出:""
解释:不存在合法字母顺序,因此返回 "" 。
提示:
1 <= words.length <= 100
1 <= words[i].length <= 100
words[i]
仅由小写英文字母组成思路
将题意搞清楚之后,这道题就变成了判断有向图时候有环,可以用拓扑排序解决。
如何搜集信息(如何建图):
a. 两层for循环枚举出所有的两个字符串的组合;
b. 然后利用指针,根据字典序规则找出信息。
edges
存储字母之间的顺序关系,其中 edges[a]
表示字母 a
后面可以跟随的字母集合。in
记录每个字母的入度,即有多少字母在它之前。cheak
标记是否出现了无效的字母顺序。add
函数,该函数比较两个单词 s1
和 s2
,找到它们第一个不相同的字母,然后将这个字母的顺序关系添加到 edges
中。如果 s2
是 s1
的前缀,则将 cheak
设置为 true
。add
函数,如果 cheak
为 true
,则直接返回空字符串。q
存储入度为 0 的字母,初始化队列时将所有入度为 0 的字母加入。BFS
进行拓扑排序,不断将入度为 0 的字母出队,并将其后面可以跟随的字母的入度减 1。将入度为 0 的字母加入结果字符串 ret
中。ret
。代码
class Solution { unordered_map<char,unordered_set<char>> edges; unordered_map<char,int> in; bool cheak=false; void add(string& s1,string& s2){ int n=min(s1.size(),s2.size()); int i=0; while(i<n){ 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<s1.size()) cheak=true; } public: string alienOrder(vector<string>& words) { for(auto& s:words) for(auto& ch:s) in[ch]=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(cheak) return ""; } queue<char> 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; } };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。