【数据结构】有向图与无向图的那些事(图、dfs、bfs、并查集)

6 篇文章 0 订阅

前言

这几天做了一些笔试题和练习题,发现大厂喜欢考一些图的题目,特此记录学习一下!

另外,秋招对我好一点!!!

太难了,今年!

有向图

举个栗子

207. 课程表

你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。
在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。
例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。
请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。

这类问题可以转换成有向图中是否有环的问题,因为如果有环,则会出现"死锁"的情况

代码如下:

class Solution {
private:
    vector<vector<int>> path;
    bool flag = true;
    vector<int> vistited;  // 用一个数组记录使用情况

    // dfs查询
    void dfs(int i){
        vistited[i] = 1;  // 查询中

        for(auto v:path[i]){
            if(vistited[v]==0){
                dfs(v);
            }else if(vistited[v]==1){  // 之前已经查询一次
                flag = false;
                return;
            }
            // if(!flag) return;  这个不用也可以
        }

        vistited[i] =2; // 查询完毕
    }
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        // 构建有向图1 0
        path.resize(numCourses);
        vistited.resize(numCourses);

        for(auto pre:prerequisites){
            path[pre[1]].push_back(pre[0]); // 先学习pre[1] 才能学习pre[0]
        }

        for(int i=0;i<numCourses && flag;++i){
            if(vistited[i]==0){
                dfs(i);
            }
        }
        return flag;
    }
};

无向图

举个栗子
547. 省份数量

有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。
省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。
返回矩阵中 省份 的数量。

使用dfs

代码如下:

class Solution {

public:

    void dfs(vector<vector<int>>& isConnected,vector<int>& visited,int n,int i){
        for(int j=0;j<n;++j){
            if(isConnected[i][j]==1 && !visited[j]){
                visited[j] = 1;  // 无向图就可以这么弄 用dfs  深度优先搜索
                dfs(isConnected,visited,n,j);
            }
        }
    }

    int findCircleNum(vector<vector<int>>& isConnected) {
        // 就是这种题目

        // 构建一个图
        int n = isConnected.size();
        if(n<=1) return n;

        vector<int> visited(n);

        int provinces = 0;

        for(int i=0;i<n;++i){ // n个城市
            if(!visited[i]){
                dfs(isConnected,visited,n,i);  // 如果
                provinces++;
            }
        }

        return provinces;
    }
 };

使用并查集

代码如下

class Solution {

public:

        // 查找算法
    int Find(vector<int> &parent,int x){
        if(parent[x]!=x){
            parent[x] = Find(parent,parent[x]);
        }
        return parent[x];
    }
        
        // 合并算法
    void Union(vector<int>& parent, int x1, int x2) {
        parent[Find(parent,x1)] = Find(parent,x2);  // 我的爸爸是你
    }

    int findCircleNum(vector<vector<int>>& isConnected) {
   

   
        int n = isConnected.size();
        if(n<=1) return n;

        // 使用并查集
        vector<int> parent(n);

        // 创建并查集
        for(int i=0;i<n;++i){
            parent[i] = i;   // 父亲是自己
        }

        // 并查集的两个操作
        // 合并
        for(int i=0;i<n;++i){
            for(int j=i+1;j<n;++j){
                if(isConnected[i][j]==1){
                    Union(parent,i,j);
                }
            }
        }

        // 结果
        int provinces = 0;
        for(int  i=0;i<n;++i){
            if(Find(parent,i)==i){
                provinces++;
            }
        }

        return provinces;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值