Leetcode1971. 寻找图中是否存在路径

LeetCode 1971题:并查集与深度优先搜索解法
博客围绕LeetCode 1971题“寻找图中是否存在路径”展开,介绍了两种解法。一是并查集,时间复杂度为O(n+m×α(m)),空间复杂度为O(n);二是深度优先搜索,从顶点source开始递归搜索,时间复杂度为O(n+m),空间复杂度为O(n+m)。

Every day a Leetcode

题目来源:1971. 寻找图中是否存在路径

解法1:并查集

并查集介绍:并查集详解

代码:

/*
 * @lc app=leetcode.cn id=1971 lang=cpp
 *
 * [1971] 寻找图中是否存在路径
 */

// @lc code=start
class UnionFind
{
    vector<int> father, size;

public:
    UnionFind(int n) : father(n), size(n, 1)
    {
        // iota函数可以把数组初始化为 0 到 n-1
        iota(father.begin(), father.end(), 0);
    }
    int find(int x)
    {
        if (x == father[x])
            return x;
        else
            return find(father[x]);
    }
    void connect(int p, int q)
    {
        int fa_p = find(p), fa_q = find(q);
        if (fa_p != fa_q)
            father[fa_p] = fa_q;
    }
    bool isConnected(int p, int q)
    {
        return find(p) == find(q);
    }
};

class Solution
{
public:
    bool validPath(int n, vector<vector<int>> &edges, int source, int destination)
    {
        UnionFind uf(n);
        for (vector<int> &edge : edges)
            uf.connect(edge[0], edge[1]);
        return uf.isConnected(source, destination);
    }
};
// @lc code=end

结果:

在这里插入图片描述

复杂度分析:

时间复杂度:O(n+m×α(m)),其中 n 是图中的顶点数,m 是图中边的数目,α 是反阿克曼函数。并查集的初始化需要 O(n) 的时间,然后遍历 m 条边并执行 m 次合并操作,最后对 source 和 destination 执行一次查询操作,查询与合并的单次操作时间复杂度是 O(α(m)),因此合并与查询的时间复杂度是 O(m×α(m)),总时间复杂度是 O(n+m×α(m))。

空间复杂度:O(n),其中 n 是图中的顶点数。并查集需要 O(n) 的空间。

解法2:深度优先搜索

首先从顶点 source 开始遍历并进行递归搜索。搜索时每次访问一个顶点 vertex 时,如果 vertex 等于 destination 则直接返回,否则将该顶点设为已访问,并递归访问与 vertex 相邻且未访问的顶点 next。如果通过 next 的路径可以访问到 destination,此时直接返回 true,当访问完所有的邻接节点仍然没有访问到 destination,此时返回 false。

代码:

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

    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(source, destination, adj, visited);
    }
};

结果:

在这里插入图片描述

复杂度分析:

时间复杂度:O(n+m),其中 n 表示图中顶点的数目,m 表示图中边的数目。

空间复杂度:O(n+m),其中 n 表示图中顶点的数目,m 表示图中边的数目。空间复杂度主要取决于邻接顶点列表、记录每个顶点访问状态的数组和递归调用栈,邻接顶点列表需要 O(m+n) 的存储空间,记录每个顶点访问状态的数组和递归调用栈分别需要 O(n) 的空间。

LeetCode 中,“寻找宝藏”这一主题通常不是直接以字面意义出现的,而是通过一些与路径探索、地遍历、机关触发等相关的题目来体现。以下是一些与“寻找宝藏”概念相关的题目及其解法思路: ### 3. 二维迷宫中寻找宝藏的路径问题 LeetCode 中有一些题目以迷宫、地路径搜索的形式出现,例如“迷宫”、“迷宫 II”、“迷宫 III”等。这些题目中,通常用字符 `'S'` 表示起点(入口),`'T'` 表示终点(宝藏位置),需要找到从起点到终点的最短路径或判断是否可达。这类问题通常使用广度优先搜索(BFS)或深度优先搜索(DFS)进行求解。 示例题目:LeetCode 505. The Maze II 解法要点:使用 BFS 遍历迷宫,记录每个点的最短路径长度,最终返回到达目标点的最短路径。 ### 130. 被机关保护的宝藏问题 类似于引用中提到的“宝藏被机关保护”的设定,LeetCode存在一些题目要求必须满足某些前置条件才能解锁目标。例如: - LeetCode 1293. Shortest Path in a Grid with Obstacles Elimination 在这个题目中,允许移除一定数量的障碍物(相当于触发机关),从而找到通往目标的路径。 解法要点:扩展的 BFS,状态包括坐标位置和剩余可移除障碍数[^3]。 ### 204. 计数质数(类比“筛选宝藏”) 虽然与字面意义的“宝藏”无关,但埃氏筛法(Sieve of Eratosthenes)的思路可以类比为“筛选出有价值的数(质数)”,在 LeetCode 中广泛用于优化计数问题。例如: - LeetCode 204. Count Primes 使用埃氏筛法高效筛选出小于 n 的所有质数,时间复杂度为 O(n log log n)[^5]。 ### 示例代码:埃氏筛法实现 ```java class Solution { public int countPrimes(int n) { int[] isPrime = new int[n]; int ans = 0; Arrays.fill(isPrime, 1); for (int i = 2; i < n; i++) { if (isPrime[i] == 1) { ans++; if ((long) i * i < n) { for (int j = i * i; j < n; j += i) { isPrime[j] = 0; } } } } return ans; } } ``` ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UestcXiye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值