LeetCode 1971[并查集 DFS BFS] 寻找图中是否存在路径 HERODING的LeetCode之路

Posted HERODING23

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 1971[并查集 DFS BFS] 寻找图中是否存在路径 HERODING的LeetCode之路相关的知识,希望对你有一定的参考价值。


这道题是LeetCode中并查集标签下唯一一道简单题,是图论知识中最简单的问题,直接套用模板就可以得到结果,并查集、DFS、BFS都可以很好解决,首先给出DFS的解法。
DFS
第一步根据给定的边构建顶点邻接矩阵,定义访问数组,然后从source出发,不断往根据其相邻的边向下搜索,访问过的顶点标记为visited,直到找到destination返回true,否则返回false,代码如下:

class Solution 
public:
    bool validPath(int n, vector<vector<int>>& edges, int source, int destination) 
        // 构建邻接矩阵
        vector<vector<int>> adj(n);
        for(auto& edge : edges) 
            int x = edge[0], y = edge[1];
            adj[x].emplace_back(y);
            adj[y].emplace_back(x);
        
        // 访问数组
        vector<bool> visited(n, false);
        return dfs(adj, source, destination, visited);
    

    bool dfs(vector<vector<int>>& adj, int source, int destination, vector<bool>& visited) 
        if(source == destination) 
            return true;
        
        visited[source] = true;
        for(auto next : adj[source]) 
            if(!visited[next] && dfs(adj, next, destination, visited)) 
                return true;
            
        
        return false;
    
;

BFS
这道题同样可以用广搜轻松解决,广搜的方法和深搜有异曲同工之妙,首先都是构造邻接矩阵和访问数组,接着从source出发,把所有与source相连接的边放入队列中,并标记为visited,如果遇到destination返回true,不断重复把队列中的顶点相连接的未被访问过的顶点放入到队列中,直到队列为空,返回false,代码如下:

class Solution 
public:
    bool validPath(int n, vector<vector<int>>& edges, int source, int destination) 
        // 构建邻接矩阵
        vector<vector<int>> adj(n);
        for(auto& edge : edges) 
            int x = edge[0], y = edge[1];
            adj[x].emplace_back(y);
            adj[y].emplace_back(x);
        
        // 访问数组
        vector<bool> visited(n, false);
        queue<int> q;
        q.push(source);
        visited[source] = true;
        while(!q.empty()) 
            int node = q.front();
            q.pop();
            if(node == destination) 
                return true;
            
            for(auto& next : adj[node]) 
                if(!visited[next]) 
                    q.push(next);
                    visited[next] = true;
                
            
        
        return false;
    
;

并查集
事实上,解决连通图问题,最便捷直接的方法还是并查集,并查集相当于一个通用的模板,因此可以封装成类,当需要使用的时候直接copy过来即可,当然直接编写也很简单,首先是定义两个数据结构,parent和rank数组,前者是记录每个节点的父标签,即所在图标签,rank是判断两图合并时到底是谁吞并谁,在本题中不起作用(谁吞谁都一样),以及定义三个函数,第一个构造函数,初始化parent和rank,每个节点初始都是一张图,所以初始parent就是本身,find函数是为了找到当前节点所在图的根节点,即图标签,connect函数是判断两个节点是否有相同的根节点,即是否在同一张图上,第三个函数是union函数,将两个图连接到一起,如果两个节点的根节点相同,则不要合并,不同的话,就把rank大的吞并rank小的图(直接修改被吞并图的parent[root]即可)。构造好并查集类后,对于本题来说简直手到擒来,直接实例化并查集类,遍历edges把点连通,然后判断source和destination是否在同一个图中,即返回uf.connect(source, destination)即可,代码如下:

class UnionFind 
private:
    vector<int> parent;
    vector<int> rank;

public:
    UnionFind(int n) 
        parent = vector<int>(n);
        rank = vector<int>(n);
        for(int i = 0; i < n; i ++) 
            parent[i] = i;
        
    

    // 返回根节点标识
    int find(int x) 
        if(parent[x] != x) 
            parent[x] = find(parent[x]);
        
        return parent[x];
     

    // 判断节点是否连接
    bool connect(int x, int y) 
        return find(x) == find(y);
    

    // 将两个连通图相连
    void unionGraph(int x, int y) 
        int rootX = find(x);
        int rootY = find(y);
        if(rootX != rootY) 
            if(rank[rootX] > rank[rootY]) 
                parent[rootY] = rootX;
             else if(rank[rootX] > rank[rootY]) 
                parent[rootX] = rootY; 
             else 
                parent[rootY] = rootX;
                rank[rootX] ++;
            
        
    
;

class Solution 
public:
    bool validPath(int n, vector<vector<int>>& edges, int source, int destination) 
        UnionFind uf(n);
        for(auto& edge : edges) 
            uf.unionGraph(edge[0], edge[1]);
        
        return uf.connect(source, destination);
    
;

以上是关于LeetCode 1971[并查集 DFS BFS] 寻找图中是否存在路径 HERODING的LeetCode之路的主要内容,如果未能解决你的问题,请参考以下文章

2/10 并查集+bfs+dfs+最短路径+spfa队列优化

PAT Advanced 1034 Head of a Gang (30) [图的遍历,BFS,DFS,并查集]

判断图连通的三种方法——dfs,bfs,并查集

求树的直径+并查集(bfs,dfs都可以)hdu4514

并查集/dfs解决——leetcode每日一题——1020飞地的数量

[LeetCode] 547. Friend Circles 朋友圈