LeetCode 332. Reconstruct Itinerary【欧拉回路,通路,DFS】困难
本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章中,我不仅会讲解多种解题思路及其优化,还会用多种编程语言实现题解,涉及到通用解法时更将归纳总结出相应的算法模板。
为了方便在PC上运行调试、分享代码文件,我还建立了相关的仓库。在这一仓库中,你不仅可以看到LeetCode原题链接、题解代码、题解文章链接、同类题目归纳、通用解法总结等,还可以看到原题出现频率和相关企业等重要信息。如果有其他优选题解,还可以一同分享给他人。
由于本系列文章的内容随时可能发生更新变动,欢迎关注和收藏征服LeetCode系列文章目录一文以作备忘。
给你一份航线列表 tickets
,其中 tickets[i] = [fromi, toi]
表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。
所有这些机票都属于一个从 JFK
(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK
开始。如果存在多种有效的行程,请你按字典排序返回最小的行程组合。
- 例如,行程
["JFK", "LGA"]
与["JFK", "LGB"]
相比就更小,排序更靠前。
假定所有机票至少存在一种合理的行程。且所有的机票 必须都用一次 且 只能用一次 。
示例 1:
输入:tickets = [["MUC","LHR"],["JFK","MUC"],["SFO","SJC"],["LHR","SFO"]]
输出:["JFK","MUC","LHR","SFO","SJC"]
示例 2:
输入:tickets = [["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]]
输出:["JFK","ATL","JFK","SFO","ATL","SFO"]
解释:另一种有效的行程是 ["JFK","SFO","ATL","JFK","ATL","SFO"] ,但是它字典排序更大更靠后。
提示:
1 <= tickets.length <= 300
tickets[i].length == 2
fromi.length == 3
toi.length == 3
fromi
和toi
由大写英文字母组成fromi != toi
本题和「753. 破解保险箱」类似,是力扣平台上为数不多的求解欧拉回路 / 欧拉通路的题目。
我们化简本题题意:给定一个 O ( n ) O(n) O(n) 个点 O ( m ) O(m) O(m) 条边的图,要求从指定的顶点出发,经过所有的边恰好一次(可以理解为给定起点的「一笔画」问题),使得路径的字典序最小。这种「一笔画」问题与欧拉图或者半欧拉图有着紧密的联系,下面给出定义:
- 通过图中所有边恰好一次且行遍所有顶点的通路称为欧拉通路;
- 通过图中所有边恰好一次且行遍所有顶点的回路称为欧拉回路;
- 具有欧拉回路的无向图称为欧拉图;
- 具有欧拉通路但不具有欧拉回路的无向图称为半欧拉图。
因为本题保证至少存在一种合理的路径,也就告诉了我们,这张图是一个欧拉图或者半欧拉图。我们只需要输出这条欧拉通路的路径即可。如果没有保证至少存在一种合理的路径,我们需要判别这张图是否是欧拉图或者半欧拉图,具体地:
- 对于无向图 G G G , G G G 是欧拉图当且仅当 G G G 是连通的且没有奇度顶点。
- 对于无向图 G G G , G G G 是半欧拉图当且仅当 G G G 是连通的且 G G G 中恰有 0 0 0 个或 2 2 2 个奇度顶点。
- 对于有向图 G G G , G G G 是欧拉图当且仅当 G G G 的所有顶点属于同一个强连通分量且每个顶点的入度和出度相同。
- 对于有向图 G G G , G G G 是半欧拉图当且仅当:
- 如果将 G G G 中的所有有向边退化为无向边时,那么 G G G 的所有顶点属于同一个强连通分量;
- 最多只有一个顶点的出度与入度差为 1 1 1 ;
- 最多只有一个顶点的入度与出度差为 1 1 1 ;
- 所有其他顶点的入度和出度相同。
让我们考虑下面的这张图:
我们从起点 J F K JFK JFK 出发,合法路径有两条:
- J F K → A A A → J F K → B B B → J F K JFK→AAA→JFK→BBB→JFK JFK→AAA→JFK→BBB→JFK
- J F K → B B B → J F K → A A A → J F K JFK→BBB→JFK→AAA→JFK JFK→BBB→JFK→AAA→JFK
既然要求字典序最小,那么我们每次应该贪心地选择当前节点所连的节点中字典序最小的那一个,并将其入栈。最后栈中就保存了我们遍历的顺序。
为了保证我们能够快速找到当前节点所连的节点中字典序最小的那一个,我们可以使用优先队列存储当前节点所连到的点,每次我们 O ( 1 ) O(1) O(1) 地找到最小字典序的节点,并 O ( log m ) O(\log m) O(logm) 地删除它。
然后我们考虑一种特殊情况:
当我们先访问 A A A AAA AAA 时,我们无法回到 J F K JFK JFK,这样我们就无法访问剩余的边了。也就是说,当我们贪心地选择字典序最小的节点前进时,我们可能先走入「死胡同」,从而导致无法遍历到其他还未访问的边。于是我们希望能够遍历完当前节点所连接的其他节点后再进入「死胡同」。
注意对于每一个节点,它只有最多一个「死胡同」分支。依据前言中对于半欧拉图的描述,只有那个入度与出度差为 1 1 1 的节点会导致死胡同。
解法 H i e r h o l z e r Hierholzer Hierholzer 算法
H i e r h o l z e r Hierholzer Hierholzer 算法用于在连通图中寻找欧拉路径,其流程如下:
- 从起点出发,进行深度优先搜索。
- 每次沿着某条边从某个顶点移动到另外一个顶点时,都需要删除这条边。
- 如果没有可移动的路径,则将所在节点加入到栈中,并返回。
当我们顺序地考虑该问题时,我们也许很难解决该问题,因为我们无法判断当前节点的哪一个分支是「死胡同」分支。不妨倒过来思考。我们注意到只有那个入度与出度差为 1 1 1 的节点会导致死胡同。而该节点必然是最后一个遍历到的节点——对于当前节点而言,走入它的每一个非「死胡同」分支进行深度优先搜索,都将会搜回到当前节点。而从它的「死胡同」分支出发进行深度优先搜索将不会搜回到当前节点。我们可以改变入栈的规则,当遍历完一个节点所连的所有节点后,才将该节点入栈(即逆序入栈),也就是说当前节点的死胡同分支始终优先于其他非「死胡同」分支入栈。
这样就能保证我们可以「一笔画」地走完所有边,且最终的栈中逆序地保存了「一笔画」的结果。我们只要将栈中的内容反转,即可得到答案。
class Solution {
public:unordered_map<string, priority_queue<string, vector<string>, std::greater<string>>> vec;vector<string> stk;void dfs(const string& curr) {while (vec.count(curr) && vec[curr].size() > 0) {string tmp = vec[curr].top();vec[curr].pop();dfs(move(tmp));}stk.emplace_back(curr);}vector<string> findItinerary(vector<vector<string>>& tickets) {for (auto& it : tickets) {vec[it[0]].emplace(it[1]);}dfs("JFK"); // JFK要么是欧拉回路的一点,要么是欧拉通路的起点 reverse(stk.begin(), stk.end());return stk;}
};
复杂度分析:
- 时间复杂度: O ( m log m ) O(m \log m) O(mlogm) ,其中 O ( m ) O(m) O(m) 是边的数量。对于每一条边我们需要 O ( log m ) O(\log m) O(logm) 地删除它,最终的答案序列长度为 m + 1 m+1 m+1 ,而与 O ( n ) O(n) O(n) 无关。
- 空间复杂度: O ( m ) O(m) O(m) ,其中 O ( m ) O(m) O(m) 是边的数量。我们需要存储每一条边。
相关文章:
LeetCode 332. Reconstruct Itinerary【欧拉回路,通路,DFS】困难
本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章…...
236. 二叉树的最近公共祖先 Python
文章目录 一、题目描述示例 1示例 2示例 3 二、代码三、解题思路 一、题目描述 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满…...
WPF中DataGrid控件绑定数据源
步骤 创建数据源:首先,我们需要创建一个数据源,可以是一个集合(如List、ObservableCollection等),也可以是一个DataTable对象。数据源中的每个元素代表一行数据。 设置DataGrid的ItemsSource属性ÿ…...
Linux arm64 set_memory_ro/rw函数
文章目录 一、函数简介1.1 简介1.2 change_memory_common1.3 __change_memory_common 二、apply_to_page_range函数2.1 apply_to_page_range2.2 apply_to_p4d_range2.3 apply_to_pud_range2.4 apply_to_pmd_range2.5 apply_to_pte_range 三、hook系统调用参考资料 一、函数简介…...
安达发|APS排单软件中甘特图的应用
近几年来,企业对生产效率和管理水平的要求越来越高。为了提高生产效率,降低生产成本,许多企业开始引入先进的生产计划与调度系统(APS),实现生产过程的自动化、智能化管理。APS排产软件是一种能够根据企业的…...
快速上手Linux基础开发工具
目录 软件包管理器 概念理解 用法示例 - 以yum为例 vim 模式的切换 常用操作 插件和配置 gcc/g gdb make / makefile 软件包管理器 概念理解 在Linux下安装软件的话,一个比较原始的办法是下载程序的源代码,然后进行编译,进而得到…...
【开发工具】idea 的全局搜索快捷键(Ctrl+shift+F)失效
文章目录 前言1. 取消 输入法的快捷键(推荐使用)2.更改 idea的快捷键3. 热键占用总结 前言 当你发现在idea 中看到用于全局搜索的快捷键就是 CtrlshiftF,可是怎么按都不管用的时候,你就不要再执着于自己的操作继续狂点电脑按键了…...
港联证券:“火箭蛋”来袭 蛋价涨势能否延续?
上个交易周(9月11日至15日),鸡蛋期货商场呈现了意想不到的涨势。9月15日,鸡蛋期货多个合约大涨,其中2310合约涨超5.6%,主力合约2311盘中两度触及涨停,最终收涨6%。业内人士以为,鸡蛋…...
Vue3_vite
使用Vue-cli创建 使用vite创建 Composition API 组合API setup 1.Vue3中的一个新的配置项,值为一个函数 2.可以将组件中所用到的数据,方法等配置在setup中. 3.setup函数的两种返回值 3.1若返回一个对象,则对象中的属性,方法,在模板中均可以直接使用. 3.2若返回一个渲染函数…...
python-字符串去掉空格的常见方法
python提供了去掉字符串空格的方法,可以满足大部分需求。 但在实际应用中,还需要灵活借助python其他方法,来实现字符串空格的删除。 比如,去掉字符串的全部空格、字符串连续空格保留一个等,都需要结合其他的方法来实现…...
如何写出一个成熟的线上线下结合的营销方案?
分享一下咱们案例库里策划的一个线上线下结合的活动的案例。 这个活动是为了推广一个新品牌,增加品牌知名度和用户粘性。 你可以根据以下几个要点来进行活动策划: 1、目标: 让目标用户了解并喜欢新品牌,激发用户参与和分享&am…...
Vc - Qt - “扩张“的窗口
该示例演示了一个"扩张的窗口",主窗口的布局为水平布局,内置两个子窗口,采用定时器设置左边窗口的宽度,达到控制"扩张"的目的。 #include <QApplication> #include <QWidget> #include <QHBox…...
vue学习-02vue入门之组件
删除Vue-cli预设 在用户根目录下(C:\Users\你的用户名)这个地址里有一个.vuerc 文件,修改或删除配置 组件 Props(组件之间的数据传递) Prop 的大小写 (camelCase vs kebab-case)不敏感Prop 类型: String Number Boolean Array Object Date Function Symbol传递静态或动态 Pr…...
解决Pycharm使用Conda激活环境失败的问题
Q:公司电脑终端使用powershell来激活conda环境时报错? 同时手动打开powershell报"profile.ps1” 无法被加载的错误 A: 1,手动打开powershell,设置管理员打开 2,打开powershell 打开 PowerShell 终端,并输入以下命令:Get-ExecutionPo…...
SpringSecurity 核心组件
文章目录 SpringSecurity 结构组件:SecurityContextHolder组件:Authentication组件:UserDetailsService组件:GrantedAuthority组件总结 SpringSecurity 结构 在SpringSecurity中的jar分为4个,作用分别为 jar作用spri…...
【Vue】快速入门和生命周期
目录 前言 一、vue的介绍 1. Vue.js是什么? 2. 库和框架的区别 3.基本概念和用法: 二、MVVM的介绍 1. 什么是MVVM? 2. MVVM的组成部分 3. MVVM的工作流程 4. MVVM的优势 5. MVVM的应用场景 三、vue实例 1.模板语法: …...
JVM架构和内存管理优化
Java虚拟机(JVM)是Java编程语言的核心组件,负责执行Java字节码并提供运行时环境,使得Java程序可以在不同的平台上运行。了解JVM的工作原理和内存管理对于优化代码性能和理解Java的内存管理和垃圾收集机制非常重要。在本文中&#…...
C语言——贪吃蛇小游戏
目录 一、ncurse 1.1 为什么需要用ncurse: 1.2 ncurse的输入输出: 1.2.1 如何使用ncurse: 1.2.2 编译ncurse的程序: 1.2.3 测试输入一个按键ncurse的响应速度: 1.3 ncurse上下左右键获取: 1.3.1 如…...
PHP8中获取并删除数组中第一个元素-PHP8知识详解
我在上一节关于数组的教程,讲的是在php8中获取并删除数组中最后一个元素,今天分享的是相反的:PHP8中获取并删除数组中第一个元素。 回顾一下昨天的知识,array_pop()函数将返回数组的最后一个元素,今天学习的是使用arr…...
EtherCAT 总线型 4 轴电机控制卡解决方案
技术特点 支持标准 100M/s 带宽全双工 EtherCAT 总线网络接口及 CoE 通信协议一 进一出(RJ45 接口),支持多组动态 PDO 分组和对象字典的自动映射,支持站 号 ID 的自动设置与保存,支持 SDO 的电机参数设置与…...
Upload-labs十六和十七关
目录 第十六关第十七关 第十六关 直接上传php文件判断限制方式: 同第十五关白名单限制 第十六关源码: 代码逻辑判断了后缀名、content-type,以及利用imagecreatefromgif判断是否为gif图片,最后再做了一次二次渲染 第71行检测…...
软件包的管理
概念 在早期Linux系统中,要想在Linux系统中安装软件只能采取编译源码包的方式进行安装,所以早期安装软件是一件非常困难、耗费耐心的事情,而且大多数服务程序仅提供源代码,还需要运维人员编译后自行解决软件之间的依赖关系。所以…...
常见入门级进销存系统合集
进销存系统是企业管理中不可或缺的一环,它们可以帮助企业有效管理库存、销售和采购等关键业务。然而,对于初创企业和小型企业来说,选择一个合适的进销存系统可能是一项挑战。在这篇文章中,我们将探讨入门级和资深级进销存系统之间…...
爬虫逆向实战(32)-某号店登录(RSA、补环境、混淆)
一、数据接口分析 主页地址:某号店 1、抓包 通过抓包可以发现登录接口是/publicPassport/login.do 2、判断是否有加密参数 请求参数是否加密? 通过查看“载荷”模块可以发现,有三个加密参数:username、password、captchaTok…...
正则表达式学习和高级用法
以下所有的验证都在 在线验证 1. 起始符 / 正则表达式的起始符2. 限定符 匹配前面的子表达式**1次或多次**。例如,zo 能匹配 "zo" 以及"zoo",但不能匹配 "z"。等价于 {1,}。 ? 匹配前面的子表达式**0次或1次**。例如…...
C# Onnx Yolov8 Fire Detect 火焰识别,火灾检测
效果 项目 代码 using Microsoft.ML.OnnxRuntime.Tensors; using Microsoft.ML.OnnxRuntime; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using Syste…...
线程安全问题
目录 一、线程安全 二、线程安全问题 三、线程安全 1.同步代码块 2.同步方法 3.Lock锁 3.1常用方法: 3.2 死锁 3.3 练习: 四、生产者和消费者(线程通信问题) 一、线程安全 如果有多个线程在同时运行,而这些…...
【力扣每日一题】2023.9.18 打家劫舍Ⅲ
目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 今天是打家劫舍3,明天估计就是打家劫舍4了。 今天的打家劫舍不太一样,改成二叉树了,不过规则没有变&…...
Docker基础学习
Docker 学习目标: 掌握Docker基础知识,能够理解Docker镜像与容器的概念 完成Docker安装与启动 掌握Docker镜像与容器相关命令 掌握Tomcat Nginx 等软件的常用应用的安装 掌握docker迁移与备份相关命令 能够运用Dockerfile编写创建容器的脚本 能够…...
esbuild中文文档-路径解析配置项(Path resolution - Alias、Conditions)
文章目录 路径解析配置项 Path resolution别名 Alias条件解析 Conditionsconditions是如何工作的 结语 哈喽,大家好!我是「励志前端小黑哥」,我带着最新发布的文章又来了! 老规矩,小手动起来~点赞关注不迷路࿰…...
网页设计实训报告保利集团/台州优化排名推广
win7中设置 了 任务栏按钮 合并 之后 就看不到文字了,省空间,但是那种合并效果 让切换没那么顺利了.所以我喜欢 从不合并按钮. 但是win7蛋疼的 在从不合并之后,文字出来了,显得很占用空间,我开东西一多,就要翻页了.切换 窗口 没那么顺利了.不爽. 于是乎,我想 即 从不合并 任务栏…...
做电子商务系统网站/晋城今日头条新闻
这个问题严格来说是肯定有的,kafka只能保证分区内的有序性。 下面是kafka作者Jay Kreps的blog中介绍kafka设计思想的一段话。 Each partition is a totally ordered log, but there is no global ordering between partitions (other than perhaps some wall-clock…...
交互式网站制作/东莞企业网站设计公司
了解生产中内部使用的API的性能是一项艰巨的任务。实际上,大多数团队还没有监控API。随着市场的变化,越来越多的团队将API监控作为Ops团队和QA团队的优先事项,因此每个版本都经过了适当的测试,并设置了一个监控器确保在生产环境中…...
wordpress 远程管理/2023引流软件
php 图片局部打马赛克 原理: 对图片中选定区域的每一像素,添加若干宽度及高度,生成矩型。而每一像素的矩型重叠在一起。就形成了马赛克效果。本例使用GD库的imagecolorat获取像素颜色,使用imagefilledrectangle画矩型。效果图&…...
专业建网站平台/网站推广优化招聘
原标题:计算机ppt辅导讲座2020年11月4日下午1:30,在竞秀南楼304,润园书院学习部请到了赵燕飞老师为大家带来了一次细致实用的计算机关于ppt的辅导讲座。同时也是为了丰富同学们的计算机知识,教同学们熟练运用计算机知识制作精美的ppt。本次讲…...
长沙产品网站建设/单个药品营销策划方案
一、昨天完成的 因为昨天课程较满,所以没有写太多的代码,在功能实现的方面并没有实质性的进展。 二、今天做的 继续Text文本框添加文字,解决不能显示的问题,添加文本框可以出现在截图区域任意位置的功能。 三、出现的问题 添加的文…...