【每日一题】重新规划路线

2023-12-13 05:13:49

Tag

【深搜】【广搜】【树】【2023-12-07】


题目来源

1466. 重新规划路线


题目解读

题目给定一张由 n个点(使用 0 到 n?1 编号),n?1 条边构成的有向图,如果忽略边的方向,就变成了一棵树。我们需要改变某些边的方向使得每个点都可以访问到 0 号点。


解题思路

今天是此类有向/无向图问题的第三天,前两天都是无向图的问题,今天看似是有向图的问题,实则是无向图的问题。

如果忽略边的方向,将每条有向边及其反向边加入到图中,那么从任意一点出发都能到达 0 号点。路径上可能会经过反向边,我们需要变更与之对应的原边的方向。需要变更的次数即为答案。

以每个点为起点进行搜索的代价会很大,因此我们考虑从 0 出发去遍历其他点,原来我们需要统计反向边的数量,现在需要统计原方向边的数量。

从 0 出发去遍历其他点有两种方法:

  • 深度优先搜索;
  • 广度优先搜索。

方法一:深度优先搜索

思路

在开始深度优先搜索之前,先根据数组 connections 建立无向图,使用 1 标记原方向的边,用 0 标记反向边。

从 0 开始遍历,访问到某个新的点时,所经过的边被标记为 1 时,就令答案加 1。最终统计得到的答案就是我们需要变更方向的最小路线数。

算法

从编号 0 开始,递归计算需要修改的边数。

class Solution {
public:
    int minReorder(int n, vector<vector<int>>& connections) {
        // 建图
        vector<vector<pair<int, int>>> g(n);
        for (auto connection : connections) {
            int x = connection[0], y = connection[1];
            g[x].push_back(make_pair(y, 1));
            g[y].push_back(make_pair(x, 0));
        }

        function<int(int, int)> dfs = [&](int x, int pa) {
            int res = 0;
            for (auto y : g[x]) {
                if (y.first != pa) {
                    res += y.second + dfs(y.first, x);
                }
            }
            return res;
        };
        return dfs(0, -1);
    }
};

复杂度分析

时间复杂度: O ( n ) O(n) O(n),建图的时间复杂度为 O ( n ) O(n) O(n),深搜的时间复杂度也是。

空间复杂度: O ( n ) O(n) O(n),最坏情况下树退化成一条链,所需栈空间为 O ( n ) O(n) O(n)

方法二:广度优先搜索

深搜与广搜比较

广度优先搜索与深度优先搜索解题思路一致,都是从节点 0 出发统计到其他节点的反边的数量。深搜是利用递归的方法计算,广搜则利用迭代的方法计算。

深搜中为了保证从 0 向其他节点搜索,给出了 y.first != pa 的限制。广搜中为了防止节点被重复计算,使用了一个数组 vis 来标记已经访问过的节点。

算法

class Solution {
public:
    int minReorder(int n, vector<vector<int>>& connections) {
        // 建图
        vector<vector<pair<int, int>>> g(n);
        for (auto connection : connections) {
            int x = connection[0], y = connection[1];
            g[x].push_back(make_pair(y, 1));
            g[y].push_back(make_pair(x, 0));
        }

        int res = 0;
        vector<int> vis(n);     // 标记节点是否被访问过
        queue<int> q;
        q.push(0);
        vis[0] = 1;
        while (!q.empty()) {
            int x = q.front();
            q.pop();
            for (auto y : g[x]) {
                if (vis[y.first] == 0) {
                    res += y.second;
                    q.push(y.first);
                    vis[y.first] = 1;
                }
            }
        }
        return res;
    }
};

复杂度分析

时间复杂度: O ( n ) O(n) O(n),建图的时间复杂度为 O ( n ) O(n) O(n),广搜的最坏时间复杂度也是。

空间复杂度: O ( n ) O(n) O(n)


写在最后

如果您发现文章有任何错误或者对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。

如果大家有更优的时间、空间复杂度的方法,欢迎评论区交流。

最后,感谢您的阅读,如果有所收获的话可以给我点一个 👍 哦。

文章来源:https://blog.csdn.net/weixin_54383080/article/details/134850609
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。