有向无环图的拓扑排序

解题思路

numCourses 相当于节点的数目
prerequisites 描述了所有的有向边
如果有向图中存在环,根据每次只Push入度为0 的节点的规则,是不可能遍历所有节点的
环的意思就是存在相互依赖关系

精简的代码

class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
 
        std::unordered_map<int , std::unordered_set<int> > linkedTable;
        std::vector<int  > inDegree(numCourses,0);
        for(int i=0;i<prerequisites.size();i++)
        {
            linkedTable[ prerequisites[i][1] ].emplace(prerequisites[i][0]);
            inDegree[prerequisites[i][0]] ++ ;
        }
        std::deque<int> q;
        for(int i=0;i<inDegree.size();i++)
        {
            if(inDegree[i]==0) q.push_back(i);
        }
        //start BFS
        int cnt=0;
        while(!q.empty()   )
        {
            auto node= q.front(); q.pop_front();
            cnt++;
            for ( const auto &  x:   linkedTable[node])
            {
                inDegree[x] --;    
                if( inDegree[x]==0 )  q.push_back(x) ;
            }
        }
        return cnt == numCourses;
    }
};

调试用代码

class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
    //   
    // 邻接表 可以很方便找到 与当前节点连接的节点
    // 入度为0 的点设置为BFS的起始点   向队列中添加新元素的规则是-1后 入度为0 的节点
        std::unordered_map<int , std::unordered_set<int> > linkedTable;
        std::vector<int  > inDegree(numCourses,0);

        // for(int i=0;i<numCourses;i++)
        // {
        //     linkedTable.emplace(std::make_pair(i,std::unordered_set<int>() ) );
        // }

        for(int i=0;i<prerequisites.size();i++)
        {
            linkedTable[ prerequisites[i][1] ].emplace(prerequisites[i][0]);
            inDegree[prerequisites[i][0]] ++ ;
        }
      
         //两个节点 一条边 
       // assert(linkedTable.size()==numCourses);
     //   assert(inDegree.size()==numCourses);

             for(auto t: linkedTable)
          {
              std::cout << t.first <<" ";
              for(auto x: t.second)
              {
                  std::cout<< x << " ";
              }
              std::cout << std::endl;
          }

        //         for(auto t: inDegree)
        // {
        //     std::cout <<t.first <<" In= " <<t.second << std::endl;
        // }

        std::deque<int> q;
        for(int i=0;i<inDegree.size();i++)
        {
            if(inDegree[i]==0) q.push_back(i);
        }
        //start BFS
        int cnt=0;
        while(!q.empty()   )
        {
            auto node= q.front(); q.pop_front();
            std::cout << node << " ";
            cnt++;
            for ( const auto &  x:   linkedTable[node])
            {
                inDegree[x] --;   //这里只更新入度表 不从邻接表删除元素是可以的
                if( inDegree[x]==0 )  q.push_back(x) ;
            }
        }
        return cnt == numCourses;
         
//e.g 3    [[1,0],[0,1], [2,1] , [1,2]]
//is   [0]  <-->   [1]  <-->   [2]
    //邻接表
        //   for(auto t: linkedTable)
        //   {
        //       std::cout << t.first <<" ";
        //       for(auto x: t.second)
        //       {
        //           std::cout<< x << " ";
        //       }
        //       std::cout << std::endl;
        //   }
        // // 2 1 
        // 1 2 0 
        // 0 1 

//入度表
        // for(auto t: inDegree)
        // {
        //     std::cout <<t.first <<" In= " <<t.second << std::endl;
        // }
        // 2 In= 1
        // 0 In= 1
        // 1 In= 2

        


        
    }
};

题目描述

你这个学期必须选修 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 <= 105
0 <= prerequisites.length <= 5000
prerequisites[i].length == 2
0 <= ai, bi < numCourses
prerequisites[i] 中的所有课程对 互不相同

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/course-schedule
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

如果采用DFS呢?

解题思路

DFS 思路 相当于以每个节点作为起始点都进行深度优先搜索
如果在递归过程中遇到一件访问的 (flag=2),说明 有环存在 ,应该及时剪枝 退出循环
因为这里的DFS用的是后续遍历 所以采用的是逆向邻接表

代码

class Solution {
public:
std::unordered_map<int , std::unordered_set<int> > linkedTable;
  //返回值 : 是否有环 
    bool dfs(int node,std::vector<int> & visited, std::vector<int> & res)
    {
        if(visited[node] ==2 ) return true  ;
        if( visited[node]==1 ) return false;
        visited[node] =2;
        for(int x : linkedTable[node] )
        {
            if(dfs(x,visited, res)) return true;
        }

        visited[node]=1;
        res.push_back(node);
        return false;

    }

    //因为DFS用到stack FILO  ,使用邻接表 
    //DFS  
    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {


        
       
        for(int i=0;i<prerequisites.size();i++)
        {
            linkedTable[ prerequisites[i][0] ].emplace(prerequisites[i][1]);
        }

          std::vector<int> visited(numCourses,0);
          std::vector<int> res;
          for(int  i=0;i<numCourses;i++) 
          {
              if(dfs(i,visited,res)) return {};  //
          }

            return res;

          


    }
};
posted @ 2021-05-19 10:15  boyang987  阅读(109)  评论(0编辑  收藏  举报