Leetcode每日一题(20200804)

今日题目

T207 课程表(中等,搜索)

题目描述

你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1 。

在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]

给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习。

示例 1:

输入: 2, [[1,0]]
输出: true
解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。

示例 2:

输入: 2, [[1,0],[0,1]]
输出: false
解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。

标签

dfs,bfs

解析

拓扑排序

对一个有向无环图G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。
简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。
(以上内容来自百度百科)

本题可视为,求一个有向图是否存在拓扑排序。

方法一:广度优先搜索

首先将不同课程之间的联系绘制成有向图。如果想要学习课程A之前必须完成课程B,那么我们从B到A连接一条有向边。

显然,如果有向图中不存在入度为0的结点,则不可能完成课程的学习,因为所有课程都需要先修其他课程,这样我们在一开始时无法学习任何课程。

如果存在入度为0的结点,则将其加入搜索队列,然后遍历其所有后继结点,并将其入度减一。如果产生了新的入度为0的结点,则继续将其加入队列。通过统计经过的结点数,判断是否遍历了所有结点,进而判断能否完成课程的学习。

方法二:深度优先搜索

我们可以将深度优先搜索与拓扑排序的求解联系起来,用一个栈存储所有已经完成搜索的结点。

假设我们当前搜索到了节点u,如果它的所有后继结点都已经搜索完成(全部在栈中),此时我们可以把u入栈。从栈顶到栈底遍历,由于u处于栈顶的位置,因此u出现在其所有后继结点之前,此时满足拓扑排序的要求。

根据这一思路,我们进行一遍深度优先搜索。每个节点进行回溯的时候,我们把该节点放入栈中,最终从栈顶到栈底的序列就是一种拓扑排序。结点一共有三种状态:未搜索,搜索中,已完成。

选取一个未搜索的结点u,将其标记为搜索中,并遍历其后继结点v。如果v为未搜索,则搜索v,待搜索完成后回溯到u。如果v为搜索中,则图中存在环,因此不能完成课程的学习。如果v为已完成,则跳过该结点。

由于我们只需要判断是否存在一种拓扑排序,而栈的作用仅仅是存放最终的拓扑排序结果,因此我们可以只记录每个节点的状态,而省去对应的栈。

C++解法

//bfs
class Solution
{
   
public:
    bool canFinish(int numCourses, vector<vector<int>> &prerequisites)
    {
   
        edge.resize(numCourses);
        in.resize(numCourses);
        //输入
        for (auto &line : prerequisites)
        {
   
            ++in[info[0]];
            edge[info[1]].push_back(info[0]);
        }
        queue<int> q;
        //将初始时入度为0的顶点加入队列
        for (int i = 0; i < numCourses; &
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值