当前位置: 首页 > article >正文

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

文章目录

  • Tag
  • 题目来源
  • 题目解读
  • 解题思路
    • 方法一:深度优先搜索
    • 方法二:广度优先搜索
  • 写在最后

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)


写在最后

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

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

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


http://www.kler.cn/a/160968.html

相关文章:

  • Linux学习笔记之组管理和权限管理
  • Vue自定义指令详解——以若依框架中封装指令为例分析
  • 手动实现h5移动端点击全屏按钮横屏展示图片,左右滑动切换,处理页面会随着手指滑动问题
  • Select,poll,epoll和IO多路复用和NIO
  • 【go从零单排】通道select、通道timeout、Non-Blocking Channel Operations非阻塞通道操作
  • 图像处理自动渲染代码
  • 【C++初阶】六、类和对象(初始化列表、static成员、友元、内部类)
  • 脉冲压缩及MATLAB仿真
  • 数组常用方法
  • 剧本杀小程序搭建:打造线上剧本杀新体验
  • HTML 块级元素与行内元素有哪些以及注意、总结
  • EasyExcel如何读取全部Sheet页数据方法
  • leetcode刷题:611.有效三角形的个数(双指针实现)
  • C++中单引号‘‘和双引号““的区别
  • Linux内核上游提交完整流程及示例
  • 多人聊天室
  • Python实现广义线性回归模型(statsmodels GLM算法)项目实战
  • Oracle 查询语句限制只选择最前面几行,和最后面几行的实现方式。
  • GAN:WGAN前作
  • 【玩转TableAgent 数据智能分析】-- 数据分析不再是专业人士的专利
  • 如何使用Net2FTP轻松部署本地Web文件管理器并远程访问管理内网资源?
  • [⑦ADRV902x]: JESD204学习笔记
  • 【Spark基础】-- 宽窄依赖
  • 【学习笔记】插值之拉格朗日插值(Lagrange)
  • springboot中@Builder注解的详细用法实例,跟数据库结合。
  • Leetcode226. 翻转二叉树