剑指Offer题目笔记32(拓扑排序)

面试题113:

面试题113

解决方案:
  1. 将课程看成图中的节点,如果两门课程存在先修顺序那么它们在图中对应的节点之间存在一条从先修课程到后修课程的边,因此这是一个有向图。
  2. 可行的修课序列实际上是图的拓扑排序序列。图中的每条边都是从先修课程指向后修课程,而拓扑排序能够保证任意一条边的起始节点一定排在终止节点的前面,因此拓扑排序得到的序列与先修顺序一定不会存在冲突,于是这个问题转变成如何求有向图的拓扑排序序列。对有向图进行拓扑排序的算法是每次找出一个入度为0的节点添加到序列中,然后删除该节点及所有以该节点为起点的边。重复这个过程,直到图为空或图中不存在入度为0的节点。
源代码:
import java.util.*;class Solution {public int[] findOrder(int numCourses, int[][] prerequisites) {Map<Integer, List<Integer>> graph = new HashMap<>();// 初始化图for (int i = 0; i < numCourses; i++) {graph.put(i, new LinkedList<Integer>());}int[] inDegrees = new int[numCourses];// 构建图和入度数组for (int[] prereq : prerequisites) {int course = prereq[0];int prerequisite = prereq[1];graph.get(prerequisite).add(course);inDegrees[course]++;}Queue<Integer> queue = new LinkedList<>();// 将入度为 0 的节点加入队列for (int i = 0; i < numCourses; i++) {if (inDegrees[i] == 0) {queue.add(i);}}List<Integer> order = new LinkedList<>();// 拓扑排序while (!queue.isEmpty()) {int course = queue.remove();order.add(course);for (int next : graph.get(course)) {inDegrees[next]--;if (inDegrees[next] == 0) {queue.add(next);}}}// 如果能够修完所有课程,则返回学习顺序;否则返回空数组return order.size() == numCourses ? order.stream().mapToInt(i -> i).toArray() : new int[0];}
}

面试题114:

面试题114

解决方案:
  1. 在排序的单词列表[“ac”,“ab”,“bc”,“zc”,“zb”]中,一共出现了4个字母,即’a’、‘b’、‘c’和’z’。需要根据单词的顺序确定这个4个字母的顺序。由于"ac"排在"ab"的前面,因此字母’c’应该排在字母’b’的前面(即’c’<’b’)。这是因为这两个单词的第1个字母相同,第2个字母不同,那么它们的第2个字母的顺序确定了两个单词的顺序。接下来两个相邻的单词是"ab"和"bc",它们的第1个字母就不同,那么它们的顺序由它们的第1个字母确定,所以’a’<’b’。类似地,可以根据"bc"排在"zc"的前面得知’b’<’z’,根据"zc"排在"zb"的前面得知’c’<’b’。
  2. 由比较排序的单词列表中两两相邻的单词可知’c’<’b’、‘a’<’b’和’b’<’z’,现在需要找出一个包含4个字母的字母序列满足已知的3个字母的大小顺序。这看起来就是一个关于拓扑排序的问题,可以将每个字母看成图中的一个节点。如果已知两个字母的大小关系,那么图中就有一条从较小的字母指向较大的字母的边。
源代码:
class Solution {public String alienOrder(String[] words) {Map<Character, Set<Character>> graph = new HashMap<>();//inDegrees保存每个节点的入度Map<Character, Integer> inDegrees = new HashMap<>();for (String word : words) {for (char ch : word.toCharArray()) {graph.putIfAbsent(ch, new HashSet<>());inDegrees.put(ch, 0);}}for (int i = 1; i < words.length; i++) {String w1 = words[i - 1];String w2 = words[i];if (w1.startsWith(w2) && !w1.equals(w2)) {return "";}//从头找出第1组不同的两个字母,在图中添加一条从较小的字母(ch1)指向较大的字母(ch2)的边。for (int j = 0; j < w1.length() && j < w2.length(); j++) {char ch1 = w1.charAt(j);char ch2 = w2.charAt(j);if (ch1 != ch2) {if (!graph.get(ch1).contains(ch2)) {graph.get(ch1).add(ch2);inDegrees.put(ch2, inDegrees.get(ch2) + 1);}break;}}}Queue<Character> queue = new LinkedList<>();for (char ch : inDegrees.keySet()) {//将入度为0的字符添加到队列中if (inDegrees.get(ch) == 0) {queue.add(ch);}}StringBuilder sb = new StringBuilder();while (!queue.isEmpty()) {char ch = queue.remove();sb.append(ch);//将以ch为起点的边删除,那么ch指向的节点的入度减一for (char next : graph.get(ch)) {inDegrees.put(next, inDegrees.get(next) - 1);if (inDegrees.get(next) == 0) {queue.add(next);}}}return sb.length() == graph.size() ? sb.toString() : "";}
}

面试题115:

面试题115

解决方案:
  1. 按照题目的要求,如果在seqs的某个序列中数字i出现在数字j的前面,那么由seqs重建的序列中数字i一定也要出现在数字j的前面。也就是说,重建序列的数字顺序由seqs的所有序列定义。可以将seqs中每个序列的每个数字看成图中的一个节点,两个相邻的数字之间有一条从前面数字指向后面数字的边。
  2. 如果得到的是有向图的拓扑排序序列,那么任意一条边的起始节点在拓扑排序序列中一定位于终止节点的前面。因此,由seqs重建的序列就是由seqs构建的有向图的拓扑排序的序列。这个问题就转变成判断一个有向图的拓扑排序序列是否唯一。
源代码:
class Solution {public boolean sequenceReconstruction(int[] nums, int[][] sequences) {Map<Integer, Set<Integer>> graph = new HashMap<>();Map<Integer, Integer> inDegrees = new HashMap<>();for (int[] sequence : sequences) {for (int num : sequence) {if (num < 1 || num > nums.length) {return false;}graph.putIfAbsent(num, new HashSet<>());inDegrees.putIfAbsent(num, 0);}for (int i = 0; i < sequence.length - 1; i++) {int num1 = sequence[i];int num2 = sequence[i + 1];if (!graph.get(num1).contains(num2)) {graph.get(num1).add(num2);inDegrees.put(num2, inDegrees.get(num2) + 1);}}}Queue<Integer> queue = new LinkedList<>();for (int num : inDegrees.keySet()) {if (inDegrees.get(num) == 0) {queue.add(num);}}List<Integer> built = new LinkedList<>();//入度为0的节点只能同时出现一个while (queue.size() == 1) {int num = queue.remove();built.add(num);for (int next : graph.get(num)) {inDegrees.put(next, inDegrees.get(next) - 1);if (inDegrees.get(next) == 0) {queue.add(next);}}}int[] result = new int[built.size()];result = built.stream().mapToInt(i -> i).toArray();return Arrays.equals(result, nums);}
}

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

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

相关文章

Web前端框架/库/工具

前言 前端从步枪&#xff08;原生js&#xff09;到了半自动武器&#xff08;jQuery&#xff09;并进化为全自动武器&#xff08;三大框架&#xff08;angular&#xff0c;react&#xff0c;vue及其生态链&#xff09;&#xff09;。 常说工欲善其事必先利其器。对于那些想要提…

【c++11】看完立马就懂--右值引用!!!

右值引用 一、什么是右值&#xff1f;什么是左值&#xff1f;二、右值引用三、右值引用的好处四、万能引用五、完美转发 一、什么是右值&#xff1f;什么是左值&#xff1f; 首先&#xff0c;当我们看到右值的时候&#xff0c;我们很自然的就会产生疑问&#xff1f; 什么的右边…

黑马鸿蒙学习5:LIST容器

LIST容器&#xff0c;其实就是如果FOREACH容器展示不全的话&#xff0c;会自动有滚动条了。要注意的是&#xff0c;LIST中必须有固定的listitem这个项&#xff0c;而且列表里面只能包含一个根组件。 必须把ROW容器放到listitem中&#xff0c;如下&#xff1a;

51、图论-岛屿数量

思路&#xff1a; 该问题要求在一个由 1&#xff08;表示陆地&#xff09;和 0&#xff08;表示水&#xff09;组成的二维网格中&#xff0c;计算岛屿的数量。岛屿被水包围&#xff0c;并且通过水平或垂直连接相邻的陆地可以形成。这个问题的核心是识别并计数网格中相连的陆地…

CSV解析

一直以为csv靠逗号&#xff08;,&#xff09;分割数据&#xff0c;那么只要用str.spilt(,,row)便可以将数据分割开。 事实证明想简单了&#xff0c;csv里还有这样的规定&#xff0c;如果数据内有双引号&#xff08;"&#xff09;和逗号&#xff08;,&#xff09;那么&…

车载电子电器架构 —— 售后诊断开发

车载电子电器架构 —— 售后诊断开发 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己…

在Postgres中,如何有效地管理大型数据库的大小和增长

文章目录 一、定期清理和维护1. VACUUM和ANALYZE2. 删除旧数据和归档 二、分区表三、压缩数据四、配置优化1. 调整维护工作负载2. 监控和日志 五、使用外部存储和扩展1. 外部表和FDW2. 扩展和插件 六、定期备份和恢复测试结论 管理大型数据库的大小和增长是数据库管理员&#x…

Java中的变量与常量

标识符 Java语言规定标识符由任意顺序的字母、下划线&#xff08;_&#xff09;、美元符号&#xff08;$&#xff09;和数字组成&#xff0c;并且第一个字符不能是数字。标识符也不能是Java中的关键字&#xff08;保留字&#xff09;。 在Java语言中&#xff0c;标识符的字母…

环境监测系统--------MQ系列气体检测模块驱动教程(保姆级教程)

⏩ 大家好哇&#xff01;我是小光&#xff0c;嵌入式爱好者&#xff0c;一个想要成为系统架构师的大三学生。 ⏩在环境检测中我们经常会用到检测气体的传感器&#xff0c;检测乙醇、甲烷、一氧化碳、氢气等等&#xff0c;博主呕心沥血对MQ系列传感器做一个史上最详细的使用教程…

网络安全产品---堡垒机

what 在网上搜索 运维审计与风险控制系统就是是堡垒机 我认为的堡垒机就是提供高效运维、认证管理、访问控制、安全审计和报表分析功能的云服务设备 实现高效运维的同时最大程度控制运维风险。 how 能够对运维人员维护过程进行全面跟踪、控制、记录、回放 支持细粒度配置…

政企版 WPS Pro 专业版注册安装教程

政企版 WPS Pro 专业版安装及激活步骤 第 1 步&#xff1a;下载压缩包&#xff08;内含注册码&#xff09;【无解压密码】。 第 2 步&#xff1a;解压缩后&#xff0c;运行 exe 文件&#xff0c;默认步骤安装即可。 第 3 步&#xff1a;安装完成后&#xff0c;新建一个 Word …

使用QQ邮箱进行登录验证

使用场景不多说&#xff0c;接下来直接看实现~ 登录到QQ邮箱&#xff0c;进入设置 打开IMAP/SMTP服务&#xff0c;记得把授权码记录下来&#xff0c;后面配置文件中需要用到 新建application的配置文件 spring:mail:# 指定邮件服务器地址host: smtp.qq.comusername: 你自己的q…

ROS 2边学边练(31)-- 管理大工程

前言 往往现实中的工程都是会包含很多节点很多参数很多主题的那种&#xff0c;如果单独通过各种ros2 run命令进行启动管理&#xff0c;恐怕难以招架&#xff0c;主要还是通过launch文件的方式进行管理&#xff0c;而launch文件也可以像节点那样按功能的不同模块化&#xff0c;最…

【学习】黑盒测试用例设计方法都有哪些

在软件测试中&#xff0c;黑盒测试是一种重要的测试方法&#xff0c;它专注于软件的外部行为&#xff0c;而不关心其内部结构和实现。黑盒测试的目标是确保软件的功能符合需求规格说明书中的要求。为了有效地进行黑盒测试&#xff0c;需要设计合理的测试用例。本文将详细介绍黑…

【Android】Activity task和Instrumentation杂谈

文章目录 activity taskInstrumentation机制参考 Android不仅可以装载众多的系统组件&#xff0c;还可以将它们跨进程组成ActivityTask&#xff0c;这个特性使得每个应用都不是孤立的。 activity task 从数据结构角度看&#xff0c;Task有先后之分&#xff0c;源码实现上采取了…

基于SpringBoot+Vue钢材销售管理系统的设计与实现

系统介绍 为了更好地发挥本系统的技术优势&#xff0c;根据钢材销售管理系统的需求&#xff0c;本文尝试以B/S经典设计模式中的Spring Boot框架&#xff0c;JAVA语言为基础&#xff0c;通过必要的编码处理、钢材销售管理系统整体框架、功能服务多样化和有效性的高级经验和技术…

高级IO简介

一、非阻塞IO 阻塞其实就是进入了休眠状态&#xff0c;交出了 CPU 控制权。 普通文件的读写操作是不会阻塞的&#xff0c;不管读写多少个字节数据&#xff0c; read() 或 write() 一定会在有限的时间内返回&#xff0c;所以普通文件一定是以非阻塞的方式进行 I/O 操作&…

【Visual Studio 2012中文版】下载安装以及使用方法

文章目录 前言一、下载安装包二、安装步骤1.双击VS2012_ULT_chs.iso文件打开2.双击vs_ultimate.exe打开安装程序3.选择要安装的功能4.软件正在安装&#xff0c;请耐心等待10分钟5.安装成功&#xff0c;点击“启动”6.激活码&#xff08;产品密钥&#xff09; 三、VS2012使用&am…

CRMEB Pro版营销功能规则解读

现在&#xff0c;无论是中小型企业拓宽渠道&#xff0c;还是传统企业转型&#xff0c;基本都在考虑布局线上&#xff0c;做微商城是一大趋势&#xff0c;相比传统第三方电商平台&#xff0c;独立部署的商城系统自主性更强&#xff0c;功能开发也更灵活。其中&#xff0c;作为电…

vue3 -- 项目使用自定义字体font-family

在Vue 3项目中使用自定义字体(font-family)的方法与在普通的HTML/CSS项目中类似。可以按照以下步骤进行操作: 引入字体文件: 首先,确保你的字体文件(通常是.woff、.woff2、.ttf等格式)位于项目中的某个目录下,比如src/assets/font/。 在全局样式中定义字体: 在你的全局…