实习面试算法准备之图论

这里写目录标题

  • 1 基础内容
    • 1.1 图的表示
    • 1.2图的遍历
  • 2 例题
    • 2.1 所有可能的路径

1 基础内容

图没啥高深的,本质上就是个高级点的多叉树而已,适用于树的 DFS/BFS 遍历算法,全部适用于图。

1.1 图的表示

图的存储在算法题中常用邻接表和邻接矩阵表示:
在这里插入图片描述在这里插入图片描述

// 邻接表
// graph[x] 存储 x 的所有邻居节点
List<Integer>[] graph;// 邻接矩阵
// matrix[x][y] 记录 x 是否有一条指向 y 的边
boolean[][] matrix;

有向加权图怎么实现?很简单呀:
如果是邻接表,我们不仅仅存储某个节点 x 的所有邻居节点,还存储 x 到每个邻居的权重,不就实现加权有向图了吗?
如果是邻接矩阵,matrix[x][y] 不再是布尔值,而是一个 int 值,0 表示没有连接,其他值表示权重,不就变成加权有向图了吗?
如果用代码的形式来表现,大概长这样:

// 邻接表
// graph[x] 存储 x 的所有邻居节点以及对应的权重
List<int[]>[] graph;// 邻接矩阵
// matrix[x][y] 记录 x 指向 y 的边的权重,0 表示不相邻
int[][] matrix;

1.2图的遍历

图怎么遍历?还是那句话,参考多叉树,多叉树的 DFS 遍历框架如下:

/* 多叉树遍历框架 */
void traverse(TreeNode root) {if (root == null) return;// 前序位置for (TreeNode child : root.children) {traverse(child);}// 后序位置
}

图和多叉树最大的区别是,图是可能包含环的,你从图的某一个节点开始遍历,有可能走了一圈又回到这个节点,而树不会出现这种情况,从某个节点出发必然走到叶子节点,绝不可能回到它自身。

所以,如果图包含环,遍历框架就要一个 visited 数组进行辅助:

// 记录被遍历过的节点
boolean[] visited;
// 记录从起点到当前节点的路径
boolean[] onPath;/* 图遍历框架 */
void traverse(Graph graph, int s) {if (visited[s]) return;// 经过节点 s,标记为已遍历visited[s] = true;// 做选择:标记节点 s 在路径上onPath[s] = true;for (int neighbor : graph.neighbors(s)) {traverse(graph, neighbor);}// 撤销选择:节点 s 离开路径onPath[s] = false;
}

注意 visited 数组和 onPath 数组的区别
类比贪吃蛇游戏,visited 记录蛇经过过的格子,而 onPath 仅仅记录蛇身。在图的遍历过程中,onPath 用于判断是否成环,类比当贪吃蛇自己咬到自己(成环)的场景。
如果让你处理路径相关的问题,这个 onPath 变量是肯定会被用到的,比如 拓扑排序 中就有运用。
这个 onPath 数组的操作很像前文 回溯算法核心套路 中做「做选择」和「撤销选择」,区别在于位置:回溯算法的「做选择」和「撤销选择」在 for 循环里面,而对 onPath 数组的操作在 for 循环外面。

回忆:
对于回溯算法,我们需要在「树枝」上做选择和撤销选择:
在这里插入图片描述
反映到代码上就是:

// DFS 算法,关注点在节点
void traverse(TreeNode root) {if (root == null) return;printf("进入节点 %s", root);for (TreeNode child : root.children) {traverse(child);}printf("离开节点 %s", root);
}// 回溯算法,关注点在树枝
void backtrack(TreeNode root) {if (root == null) return;for (TreeNode child : root.children) {// 做选择printf("从 %s 到 %s", root, child);backtrack(child);// 撤销选择printf("从 %s 到 %s", child, root);}
}

另一种解释就是,如果用回溯的方法遍历树,你会发现根节点被漏掉了:

void traverse(TreeNode root) {if (root == null) return;for (TreeNode child : root.children) {printf("进入节点 %s", child);traverse(child);printf("离开节点 %s", child);}
}

所以对于这里「图」的遍历,我们应该用 DFS 算法,即把 onPath 的操作放到 for 循环外面,否则会漏掉记录起始点的遍历。
说了这么多 onPath 数组,再说下 visited 数组,其目的很明显了,由于图可能含有环,visited 数组就是防止递归重复遍历同一个节点进入死循环的。

当然,如果题目告诉你图中不含环,可以把 visited 数组都省掉,基本就是多叉树的遍历。

2 例题

2.1 所有可能的路径

给你一个有 n 个节点的 有向无环图(DAG),请你找出所有从节点 0 到节点 n-1 的路径并输出(不要求按特定顺序)
graph[i] 是一个从节点 i 可以访问的所有节点的列表(即从节点 i 到节点 graph[i][j]存在一条有向边)

示例1:
在这里插入图片描述
输入:graph = [[1,2],[3],[3],[]]
输出:[[0,1,3],[0,2,3]]
解释:有两条路径 0 -> 1 -> 3 和 0 -> 2 -> 3

代码以及思路:
解法很简单,以 0 为起点遍历图,同时记录遍历过的路径,当遍历到终点时将路径记录下来即可。
既然输入的图是无环的,我们就不需要 visited 数组辅助了,直接套用图的遍历框架:

class Solution {List<List<Integer>> res = new ArrayList();public List<List<Integer>> allPathsSourceTarget(int[][] graph) {List<Integer> path = new ArrayList();traverse(graph,0,path);return res;}public void traverse(int[][] graph,int s,List<Integer> path){path.add(s);int n = graph.length;if(s == n-1){res.add(new ArrayList(path));}for(int i:graph[s]){traverse(graph,i,path);}path.removeLast();}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/829957.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

84.柱形图中最大的矩阵

二刷终于能过了. 思路解析: 不愧是hard,第一步就很难想, 对于每一个矩阵,我们要想清楚怎么拿到最大矩阵, 对于每个height[i],我们需要找到left和right,left是i左边第一个小于height[i]的,right是右边第一个小于height[i]的,那么他的最大矩阵就是height[i] * (right-left-…

linux下安装deepspeed

安装步骤 一开始安装deepspeed不可以使用pip直接进行安装。 这时我们需要利用git进行clone下载到本地&#xff1a; git clone https://github.com/microsoft/DeepSpeed.git 进入到deepspeed的安装目录下 cd /home/bingxing2/ailab/group/ai4agr/wzf/Tools/DeepSpeed 激活…

LeetCode-旋转链表

每日一题&#xff0c;很久没做链表的题了&#xff0c;今天做l一道相对简单的力扣中等难度题。 题目要求 给你一个链表的头节点 head &#xff0c;旋转链表&#xff0c;将链表每个节点向右移动 k 个位置。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], k 2 输出&…

智慧浪潮下的产业园区:洞察智慧化转型如何打造高效、绿色、安全的新园区

目录 一、引言 二、智慧化转型的内涵与价值 三、打造高效园区的智慧化策略 1、建设智能化基础设施 2、推广智能化应用 3、构建智慧化服务平台 四、实现绿色园区的智慧化途径 1、推动绿色能源应用 2、实施绿色建筑设计 3、加强环境监测与治理 五、保障园区安全的智慧…

大白菜启动U盘想格式化但格式化不了

部分区域被修改分区表保护起来了。直接格式化的话&#xff0c;里面的文件夹都还在。根本格式化不了。特别是可用容量并未还原出来。 进入计算机管理》磁盘管理&#xff0c;看到U盘盘符。别搞错了。删除掉里面的已经分的区域和未分区区域&#xff0c;让它还原成一个整体。退出。…

Webpack-入门

定义 静态模块&#xff1a;指的是编写代码过程中的html&#xff0c;css&#xff0c;js&#xff0c;图片等固定内容的文件 打包&#xff1a;把静态模块内容压缩、整合、翻译等&#xff08;前端工程化&#xff09; 1&#xff09;把less/sass转成css代码 2&#xff09;把ES6降级…

webpack 入口和出口的最佳实践

入口和出口的最佳实践 {ignore} 具体情况具体分析 下面是一些经典场景 一个页面一个JS 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 源码结构 |—— src|—— pageA 页面A的代码目录|—— index.js 页面A的启动模块|—— ...|—— pageB 页面…

matlab学习007-已知离散时间系统的系统函数并使用matlab绘制该系统的零极点图;判断系统的稳定性;幅频和相频特性曲线

目录 题目 离散时间系统的系统函数&#xff1a;H(z)(3*z^3-5*z^210z)/(z^3-3*z^27*z-5) 1&#xff0c;绘制该系统的零极点图 1&#xff09;零极点图 2&#xff09;代码 2&#xff0c;判断系统的稳定性 1&#xff09;判断结果 2&#xff09;代码 3&#xff0c;试用MATL…

闲话 ASP.NET Core 数据校验(一):内置数据校验

前言 所谓输入的是垃圾&#xff0c;输出也必然是垃圾&#xff0c;有多少安全问题隐藏在请求的数据中&#xff0c;所以永远不能相信来自用户端的输入。 对请求数据的合法性进行校验&#xff0c;不仅有助于提升用户界面的友好性&#xff0c;而且有助于提高后台程序的安全性和稳…

【车载开发系列】UDS诊断时间参数说明

【车载开发系列】UDS诊断时间参数说明 一. 应用层诊断时间参数 1&#xff09;P2 CAN_Client 诊断仪成功发送诊断报文请求之后到收到 ECU回复诊断响应的超时时间间隔 2&#xff09;P2 CAN_Server ECU 接收到诊断请求之后到开始发送诊断报文的时间间隔&#xff0c;一般默认最…

二维码门楼牌管理应用平台建设:场所检查的新模式

文章目录 前言一、二维码门楼牌管理应用平台的优势二、场所检查记录的重要性三、二维码门楼牌管理应用平台在场所检查中的应用四、二维码门楼牌管理应用平台的未来展望 前言 随着信息技术的飞速发展&#xff0c;二维码作为一种高效、便捷的信息识别方式&#xff0c;正逐渐渗透…

服务器数据恢复—存储硬盘坏道,指示灯亮黄色的数据恢复案例

服务器数据恢复环境&故障&#xff1a; 一台某品牌EqualLogic PS系列某型号存储&#xff0c;存储中有一组由16块SAS硬盘组建的RAID5磁盘阵列&#xff0c;RAID5上划分VMFS文件系统存放虚拟机文件。存储系统上层一共分了4个卷。 raid5阵列中磁盘出现故障&#xff0c;有2块硬盘…

二极管钳位型光伏逆变并网建模simulink仿真

整理了二极管钳位型光伏逆变并网建模simulink仿真&#xff0c;效果明显&#xff0c;附赠仿真报告。适合小白 二极管钳位型光伏逆变并网是将光伏发电系统中的直流电能转换为交流电能&#xff0c;并与电网连接。在此仿真中使用最大功率点追踪&#xff08;MPPT&#xff09;技术&a…

基于CANoe从零创建以太网诊断工程(2)—— TCP/IP Stack 配置的三种选项

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…

微信第三方开放平台,实现代公众号保留排版样式和图片发布文章

大家好&#xff0c;我是小悟 要想实现代公众号发布文章的功能&#xff0c;就得接入富文本编辑器&#xff0c;市面上富文本编辑器有很多&#xff0c;轻量的、重量的都有。 从开发者的角度&#xff0c;自然把轻量作为第一选择&#xff0c;因为好对接&#xff0c;怎么方便怎么来…

在win下,python如何调用.so库

#撰写c代码 #通过gcc命令编译成.so库 gcc -shared -o ./lib/pointlib.so point.c #python调用.so库 #运行结果 觉得本文对你有用&#xff0c;麻烦点赞或关注或收藏&#xff0c;你的肯定是我创作的无限动力&#xff0c;谢谢&#xff01;&#xff01;&#xff01;

制作一个RISC-V的操作系统十四-任务同步和锁

文章目录 并发与同步临界区和锁锁死锁解决死锁自旋锁&#xff08;spin lock&#xff09;原子性问题原子操作实现amoswap.w.aq例子 另一种方法自旋锁的注意事项代码其他同步技术 并发与同步 控制流&#xff1a;可理解为任务或进程 中断也可以理解为一个切换到另一个任务&#…

C++智能指针详解

目录 一. 智能指针初识 1.1 什么是智能指针 1.2 智能指针历史历程 1.3 为什么需要智能指针 1.3.1 内存泄漏 1.3.2 防止内存泄漏 1.3.3 异常的重新捕获 二. 智能指针的原理与使用 2.1 智能指针的原理 2.2 智能指针的使用 2.3 智能指针的拷贝问题…

docker网络和模式

Docker使用Linux桥接&#xff0c;在宿主机虚拟一个Docker容器网桥(docker0)&#xff0c;Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址&#xff0c;称为container-IP&#xff0c;同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个…

mars3d开发过程中点击面图层飞行定位,设置俯仰角度后,layer.flyTo({没有生效的排查思路

mars3d开发过程中点击面图层飞行定位&#xff0c;设置俯仰角度后&#xff0c;layer.flyTo({没有生效的排查思路记录&#xff0c;给大家提供一下以后排查定位问题的方向 问题场景相关代码&#xff1a; 1.项目本身代码&#xff1a; 2.精简了关键性代码后&#xff0c;就可以去ge…