• LeetCode力扣刷题——指针三剑客之三:图



    一、数据结构介绍

            作为指针三剑客之三,图是树的升级版。图通常分为有向(directed)或无向(undirected),有 循环(cyclic)或无循环(acyclic),所有节点相连(connected)或不相连(disconnected)。树即是 一个相连的无向无环图,而另一种很常见的图是有向无环图(Directed Acyclic Graph,DAG)。

    有向无环图样例

             图通常有两种表示方法。假设图中一共有 n 个节点、m 条边。

            第一种表示方法是邻接矩阵 (adjacency matrix):我们可以建立一个 n× n 的矩阵 G,如果第 i 个节点连向第 j 个节点,则 G[i][j] = 1,反之为 0;如果图是无向的,则这个矩阵一定是对称矩阵,即 G[i][j] = G[j][i]。

            第二种表示 方法是邻接链表(adjacency list):我们可以建立一个大小为 n 的数组,每个位置 i 储存一个数组或者链表,表示第 i 个节点连向的其它节点。邻接矩阵空间开销比邻接链表大,但是邻接链表不支持快速查找 i 和 j 是否相连,因此两种表示方法可以根据题目需要适当选择。除此之外,我们也可以直接用一个 m × 2 的矩阵储存所有的边。


    二、经典问题

    1. 二分图

            二分图算法也称为染色法,是一种广度优先搜索。如果可以用两种颜色对图中的节点进行着 色,并且保证相邻的节点颜色不同,那么图为二分。

    785. 判断二分图

    785. Is Graph Bipartite?

            存在一个无向图 ,图中有 n 个节点。其中每个节点都有一个介于 0 到 n - 1 之间的唯一编号。给你一个二维数组 graph ,其中 graph[u] 是一个节点数组,由节点 u 的邻接节点组成。形式上,对于 graph[u] 中的每个 v ,都存在一条位于节点 u 和节点 v 之间的无向边。该无向图同时具有以下属性:
            不存在自环(graph[u] 不包含 u)。
            不存在平行边(graph[u] 不包含重复值)。
            如果 v 在 graph[u] 内,那么 u 也应该在 graph[v] 内(该图是无向图)
            这个图可能不是连通图,也就是说两个节点 u 和 v 之间可能不存在一条连通彼此的路径。
            二分图 定义:如果能将一个图的节点集合分割成两个独立的子集 A 和 B ,并使图中的每一条边的两个节点一个来自 A 集合,一个来自 B 集合,就将这个图称为 二分图 。

            如果图是二分图,返回 true ;否则,返回 false 。

            利用队列和广度优先搜索,我们可以对未染色的节点进行染色,并且检查是否有颜色相同的 相邻节点存在。注意在代码中,我们用 0 表示未检查的节点,用 1 和 2 表示两种不同的颜色。

            注意输入的是邻接链表表示的图。

    1. class Solution {
    2. public:
    3. bool isBipartite(vectorint>>& graph) {
    4. int n = graph.size();
    5. if(n == 0) return true;
    6. vector<int> color(n, 0);
    7. queue<int> q;
    8. for(int i=0; i
    9. if(color[i] == 0){
    10. q.push(i);
    11. color[i] = 1;
    12. }
    13. while(!q.empty()){
    14. int node = q.front();
    15. q.pop();
    16. for(const int& j: graph[node]){
    17. if(color[j] == 0){
    18. q.push(j);
    19. color[j] = color[node] == 2? 1: 2;
    20. }else if(color[j] == color[node]){
    21. return false;
    22. }
    23. }
    24. }
    25. }
    26. return true;
    27. }
    28. };

    2. 拓扑排序

            拓扑排序(topological sort)是一种常见的,对有向无环图排序的算法。给定有向无环图中的 N 个节点,我们把它们排序成一个线性序列;若原图中节点 i 指向节点 j,则排序结果中 i 一定在 j 之前。拓扑排序的结果不是唯一的,只要满足以上条件即可。

    210. 课程表 II

    210. Course Schedule II

            现在你总共有 numCourses 门课需要选,记为 0 到 numCourses - 1。给你一个数组 prerequisites ,其中 prerequisites[i] = [ai, bi] ,表示在选修课程 ai 前 必须 先选修 bi 。

            例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示:[0,1] 。
            返回你为了学完所有课程所安排的学习顺序。可能会有多个正确的顺序,你只要返回 任意一种 就可以了。如果不可能完成所有课程,返回 一个空数组 。

            我们可以先建立一个邻接矩阵表示图,方便进行直接查找。这里注意我们将所有的边反向, 使得如果课程 i 指向课程 j,那么课程 i 需要在课程 j 前面先修完。这样更符合我们的直观理解。 拓扑排序也可以被看成是广度优先搜索的一种情况:我们先遍历一遍所有节点,把入度为 0 的节点(即没有前置课程要求)放在队列中。在每次从队列中获得节点时,我们将该节点放在目 前排序的末尾,并且把它指向的课程的入度各减 1;如果在这个过程中有课程的所有前置必修课 都已修完(即入度为 0),我们把这个节点加入队列中。当队列的节点都被处理完时,说明所有的 节点都已排好序,或因图中存在循环而无法上完所有课程。

    1. class Solution {
    2. public:
    3. vector<int> findOrder(int numCourses, vectorint>>& prerequisites) {
    4. vectorint>> graph(numCourses, vector<int>());
    5. vector<int> indegree(numCourses, 0);
    6. vector<int> res;
    7. for(auto& prerequisite: prerequisites){
    8. graph[prerequisite[1]].push_back(prerequisite[0]);
    9. ++indegree[prerequisite[0]];
    10. }
    11. queue<int> q;
    12. for(int i=0; isize(); ++i){
    13. if(indegree[i] == 0){
    14. q.push(i);
    15. }
    16. }
    17. while(!q.empty()){
    18. int u = q.front();
    19. q.pop();
    20. res.push_back(u);
    21. for(auto& v: graph[u]){
    22. --indegree[v];;
    23. if(indegree[v] == 0){
    24. q.push(v);
    25. }
    26. }
    27. }
    28. for(int i=0; isize(); ++i){
    29. if(indegree[i]){
    30. return vector<int>();
    31. }
    32. }
    33. return res;
    34. }
    35. };

    三、巩固练习


    欢迎大家共同学习和纠正指教

  • 相关阅读:
    设计模式之观察者模式(十四)
    TMK1TTA OSN1800全新板卡10路任意速率业务支路处理板
    在三维项目前端开发中用THREEMesh创建网格对象设置几何体和材质
    第24集丨人生的智慧:做人之道“成色”比“斤两”更重要
    robocode 相关的总结
    企业微信自建应用开发流程
    C++ Reference: Standard C++ Library reference: C Library: cmath: copysign
    C专家编程 第10章 再论指针 10.7 使用指针创建和使用动态数组
    BFO Publisher轻松将HTML转换为PDF
    SpringBoot多环境启动方案
  • 原文地址:https://blog.csdn.net/Hello_world_n/article/details/127937923