[LeetCode] Course Schedule I (207) & II (210) 解题思路

时间:2022-10-03 13:24:43

207. Course Schedule

There are a total of n courses you have to take, labeled from 0 to n - 1.

Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]

Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?

For example:

2, [[1,0]]

There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.

2, [[1,0],[0,1]]

There are a total of 2 courses to take. To take course 1 you should have finished course 0, and to take course 0 you should also have finished course 1. So it is impossible.

问题:已知课程数量,以及各个课程间的依赖关系,求是否可以满足所有依赖关系把课程上完。

这是典型的拓扑排序应用场景。是否满足所有依赖关系,实际上就是求,在课程为节点、依赖关系为边的图中,是否存在环。若存在还,则不可能满足所有依赖关系把课程上完,反之,则可能。

使用DFS 方式遍历图中的节点。使用白、灰、黑三种颜色表示 DFS 在图中遍历进度。

当前节点被访问时的颜色含义:

  • 白色:当前节点首次被访问。说明可以继续深度探索。
  • 灰色:当前节点已在当前的 DFS 路径中。说明存在环。
  • 黑色:当前节点已经从节点出发的后续路径已全部被访问。

判断1 : 一个节点以及从该节点出发的后续路径是否存在环:

  • 若该节点为白色,则将颜色改为灰色,表示该节点已在搜索路径上。继续深度遍历节点的邻居节点,直达所有邻接节点已经邻居节点的后续节点都已全部被访问,将该节点改为黑色。不存在环。
  • 若该节点为灰色,表示该节点以及在 DFS 搜索路径上,存在环。退出程序。
  • 若该节点为黑色,表示节点已经后续路径已全部被访问,无需在探索。不存在环。

对所有节点都进行判断1 检查,即可知道图中是否存在环。

 const int WHITE = ;
const int GRAY = ;
const int BLACK = ; class gnode{
public:
int val;
int col;
vector<gnode*> neighbours; gnode(int val){
this->val = val;
}
}; // 当要访问的节点颜色为灰色时,表示该节点已在搜索路径中,则形成了环。有还,无法完成。
bool canFinshNode(gnode* node){ if (node->col == WHITE) {
node->col = GRAY;
}else if(node->col == BLACK){
return true;
}else{
// be gray
return false;
} for (int i = ; i < node->neighbours.size(); i++) {
gnode* tmpn = node->neighbours[i];
bool res = canFinshNode(tmpn);
if (res == false) {
return false;
}
} node->col = BLACK; return true;
} bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) { map<int, gnode*> val_node;
for (int i = ; i < numCourses; i++) {
gnode* node = new gnode(i);
node->col = WHITE;
val_node[i] = node;
} pair<int, int> pp;
for (int i = ; i < prerequisites.size(); i++) {
pp = prerequisites[i];
val_node[pp.second]->neighbours.push_back(val_node[pp.first]);
} map<int, gnode*>::iterator m_iter;
for (m_iter = val_node.begin(); m_iter != val_node.end(); m_iter++) {
if (m_iter->second->col == WHITE) { bool res = canFinshNode(m_iter->second);
if (res == false) {
return false;
}
}
} return true;
}

210. Course Schedule II

There are a total of n courses you have to take, labeled from 0 to n - 1.

Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]

Given the total number of courses and a list of prerequisite pairs, return the ordering of courses you should take to finish all courses.

There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all courses, return an empty array.

For example:

2, [[1,0]]

There are a total of 2 courses to take. To take course 1 you should have finished course 0. So the correct course order is [0,1]

4, [[1,0],[2,0],[3,1],[3,2]]

There are a total of 4 courses to take. To take course 3 you should have finished both courses 1 and 2. Both courses 1 and 2 should be taken after you finished course 0. So one correct course order is [0,1,2,3]. Another correct ordering is[0,2,1,3].

问题:和上面问题相似,不同的是需要额外求出可行的一个课程安排顺序。

典型的拓扑排序问题,而且这次需要求确切的拓扑顺序。

虽然 问题1 中的代码只回答了是否有可能存在拓扑顺序,但是,实际上在求解过程中已经将拓扑顺序求出来了。所有只需要将少量代码,将求出的顺序保存并返回即可。

当一个节点变为黑色,则表示该节点课程所依赖的后续课程都已排序,新变黑得节点就是下一个被排序的课程。

 const int WHITE = ;
const int GRAY = ;
const int BLACK = ; class gnode{
public:
int val;
int col;
vector<gnode*> neighbours; gnode(int val){
this->val = val;
}
}; vector<int> resVec; /**
* To varify if the path which souce is node has a circle .
* If has a circle, return false;
* If has no circle, push node into res vector after visit the neighbours of node, and return true;
*
*/
bool visit(gnode* node){ if (node->col == WHITE) {
node->col = GRAY;
}else if (node->col == BLACK){
return true;
}else{
// be Gray, has a circle.
return false;
} for (int i = ; i < node->neighbours.size(); i++) {
gnode* tmp = node->neighbours[i];
int res = visit(tmp);
if (res == false) {
return false;
}
} node->col = BLACK; resVec.push_back(node->val); return true;
} vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) { vector<int> emptyV; // draw the graph representing the prerequisities relationship
map<int, gnode*> val_node;
for (int i = ; i < numCourses; i++) {
gnode* node = new gnode(i);
node->col = WHITE;
val_node[i] = node;
} for (int i = ; i < prerequisites.size(); i++) {
pair<int, int> pp = prerequisites[i];
val_node[pp.second]->neighbours.push_back(val_node[pp.first]);
} map<int, gnode*>::iterator m_iter;
for (m_iter = val_node.begin(); m_iter != val_node.end(); m_iter++) {
if (m_iter->second->col == WHITE) {
bool res = visit(m_iter->second);
if (res == false) {
return emptyV;
}
}
} // has a variable order
vector<int> resOdr(resVec.size());
for (int i = ; i < resVec.size(); i++) {
resOdr[i] = resVec[resVec.size() - i - ];
} return resOdr;
}

参考思路:

《算法导论》22.3 深度优先搜索, P349

《算法导论》22.4 拓扑排序, P355

[LeetCode] Course Schedule I (207) & II (210) 解题思路的更多相关文章

  1. &lbrack;LeetCode&rsqb; Subsets I &lpar;78&rpar; &amp&semi; II &lpar;90&rpar; 解题思路,即全组合算法

    78. Subsets Given a set of distinct integers, nums, return all possible subsets. Note: Elements in a ...

  2. &lbrack;LeetCode&rsqb; Search in Rotated Sorted Array I &lpar;33&rpar; &amp&semi;&amp&semi; II &lpar;81&rpar; 解题思路

    33. Search in Rotated Sorted Array Suppose a sorted array is rotated at some pivot unknown to you be ...

  3. leetCode 90&period;Subsets II(子集II) 解题思路和方法

    Given a collection of integers that might contain duplicates, nums, return all possible subsets. Not ...

  4. leetCode 81&period;Search in Rotated Sorted Array II (旋转数组的搜索II) 解题思路和方法

    Follow up for "Search in Rotated Sorted Array": What if duplicates are allowed? Would this ...

  5. leetCode 82&period;Remove Duplicates from Sorted List II (删除排序链表的反复II) 解题思路和方法

    Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numb ...

  6. &lbrack;LeetCode&rsqb; 160&period; Intersection of Two Linked Lists 解题思路

    Write a program to find the node at which the intersection of two singly linked lists begins. For ex ...

  7. &lbrack;LeetCode&rsqb; 3&period; Longest Substring Without Repeating Characters 解题思路

    Given a string, find the length of the longest substring without repeating characters. For example, ...

  8. &lbrack;LeetCode&rsqb; 129&period; Sum Root to Leaf Numbers 解题思路

    Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number ...

  9. leetCode 34&period;Search for a Range &lpar;搜索范围&rpar; 解题思路和方法

    Search for a Range Given a sorted array of integers, find the starting and ending position of a give ...

随机推荐

  1. jQuery Mobile 表单基础

    jQuery Mobile 会自动为 HTML 表单添加优异的便于触控的外观. jQuery Mobile 表单结构 jQuery Mobile 使用 CSS 来设置 HTML 表单元素的样式,以使其 ...

  2. Merge Into

    Merge Into [dbo].[Student] S using [10.58.8.224\TEST].[TestDb].[dbo].[Student] T on S.ID=T.ID WHEN M ...

  3. zookeeper集群一次性启动

    编写shell脚本 新建文本,命名为start-zookeeper.sh #!/bin/sh echo "start zkServer…" for i in master work ...

  4. Swagger服务API治理详解

    swager2的简介 在App后端开发中经常需要对移动客户端(Android.iOS)提供RESTful API接口,在后期版本快速迭代的过程中,修改接口实现的时候都必须同步修改接口文档,而文档与代码 ...

  5. vue内置指令详解——小白速会

    指令 (Directives) 是带有 v- 前缀的特殊属性,职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM. 内置指令 1.v-bind:响应并更新DOM特性:例如:v-bi ...

  6. iOS监听模式系列之对APNs的认知与理解

    前言: APNs 协议在近两年的 WWDC 上改过两次, 15 年 12 月 17 日更是推出了革命性的新特性.但在国内传播的博客.面试题里关于 APNs 的答案全都是旧的.错的. 导航: 对 APN ...

  7. git 冲突解决的方法

    版权声明:本文为博主原创文章,未经博主同意不得转载. 新博客地址:www.atomicdevelop.com https://blog.csdn.net/believer123/article/det ...

  8. 动态规划-----hdu 1024 &lpar;区间连续和&rpar;

    给定一个长度为n的区间:求m段连续子区间的和 最大值(其中m段子区间互不相交) 思路: dp[i][j]: 前j个元素i个连续区间最大值 (重要 a[j]必须在最后一个区间内) 转移方程:dp[i][ ...

  9. 【事务隔离级别】数据库事务隔离级别-UNDERSTANDING ISOLATION LEVELS

    参考链接:ISOLATION LEVELS ISOLATION LEVELS In a database system, concurrent transactions are processed i ...

  10. &lbrack;Baltic2013&rsqb;ballmachine BZOJ3133

    分析: 我们考虑,因为每次放置的时候,都是向子树中含有的编号最小的哪一个走,那么放置的顺序是固定的,我们将边以to的子树最小排序,之后得到的出栈序就是球的放入顺序.目测可以使用堆来实现,线段树也能实现 ...