LeetCode - Medium中Reconstruct Itinerary的示例分析

发布时间:2021-09-18 14:11:18 作者:柒染
来源:亿速云 阅读:176
# LeetCode - Medium中Reconstruct Itinerary的示例分析

## 目录
- [问题描述与背景](#问题描述与背景)
- [基础概念解析](#基础概念解析)
  - [欧拉路径与哈密尔顿路径](#欧拉路径与哈密尔顿路径)
  - [有向图与邻接表](#有向图与邻接表)
- [暴力解法与局限性](#暴力解法与局限性)
- [Hierholzer算法详解](#hierholzer算法详解)
  - [算法核心思想](#算法核心思想)
  - [递归实现步骤](#递归实现步骤)
  - [迭代实现对比](#迭代实现对比)
- [代码实现与优化](#代码实现与优化)
  - [Python版本解析](#python版本解析)
  - [Java版本关键点](#java版本关键点)
  - [时间复杂度分析](#时间复杂度分析)
- [示例推演与Debug过程](#示例推演与debug过程)
  - [标准测试案例](#标准测试案例)
  - [边界条件测试](#边界条件测试)
  - [循环机票处理](#循环机票处理)
- [变种问题探讨](#变种问题探讨)
  - [多解情况处理](#多解情况处理)
  - [无效行程检测](#无效行程检测)
  - [加权机票场景](#加权机票场景)
- [总结与学习要点](#总结与学习要点)
- [参考资料](#参考资料)

## 问题描述与背景

**题目编号**:332  
**难度**:Medium  
**通过率**:约42%  

给定一组机票(出发地,目的地),重构行程形成有效路径。所有机票必须且只能使用一次,路径需满足:
1. 从"JFK"出发
2. 字典序最小的行程
3. 形成完整欧拉路径

示例输入:
```python
tickets = [["MUC","LHR"],["JFK","MUC"],["SFO","SJC"],["LHR","SFO"]]

示例输出:

["JFK","MUC","LHR","SFO","SJC"]

基础概念解析

欧拉路径与哈密尔顿路径

特性 欧拉路径 哈密尔顿路径
定义 经过每条边恰好一次 经过每个顶点恰好一次
判定条件 有向图:入度=出度(起点终点除外) NP完全问题
本问题关联 必须使用所有机票(边) 不适用

有向图与邻接表

构建邻接表的Python示例:

from collections import defaultdict

graph = defaultdict(list)
for src, dst in sorted(tickets):  # 提前排序保证字典序
    graph[src].append(dst)

暴力解法与局限性

全排列法: 1. 生成所有可能的机票排列 2. 检查是否构成有效路径 3. 选择字典序最小解

缺陷分析: - 时间复杂度:O(n!) - 空间复杂度:O(n) - 当n=100时,计算量达9.3e+157次操作

Hierholzer算法详解

算法核心思想

graph TD
    A[选择起点JFK] --> B[深度优先遍历]
    B --> C{是否无路可走?}
    C -->|是| D[加入路径]
    C -->|否| B
    D --> E[反向构建路径]

递归实现步骤

Python关键代码:

def dfs(node):
    while graph[node]:
        dfs(graph[node].pop(0))
    route.append(node)

迭代实现对比

Java栈实现:

LinkedList<String> stack = new LinkedList<>();
stack.push("JFK");
while (!stack.isEmpty()) {
    while (!graph.get(stack.peek()).isEmpty()) {
        stack.push(graph.get(stack.peek()).poll());
    }
    route.addFirst(stack.pop());
}

代码实现与优化

Python版本解析

完整解法:

def findItinerary(tickets):
    graph = defaultdict(list)
    for src, dst in sorted(tickets):
        graph[src].append(dst)
    
    route = []
    def dfs(node):
        while graph[node]:
            dfs(graph[node].pop(0))
        route.append(node)
    
    dfs("JFK")
    return route[::-1]

Java版本关键点

优化技巧: 1. 使用PriorityQueue自动排序 2. 链表头插法避免反转 3. 栈的线程安全选择

时间复杂度分析

示例推演与Debug过程

标准测试案例

输入:

[["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]]

执行过程: 1. JFK → ATL (选择字典序较小者) 2. ATL → JFK 3. JFK → SFO 4. SFO → ATL 5. ATL → SFO

输出:

["JFK","ATL","JFK","SFO","ATL","SFO"]

边界条件测试

单程票情况: 输入:[["JFK","LAX"]] 输出:["JFK","LAX"]

循环机票: 输入:[["JFK","ABC"],["ABC","JFK"],["JFK","XYZ"]] 输出:["JFK","ABC","JFK","XYZ"]

变种问题探讨

多解情况处理

当存在多个字典序最小解时,算法天然选择第一条找到的路径。如需全部解,需修改为:

results = []
def dfs(node, path):
    if 没有剩余机票:
        results.append(path)
        return
    for i, neighbor in enumerate(graph[node]):
        dfs(neighbor, path+[neighbor])
        graph[node].insert(i, neighbor)  # 回溯

无效行程检测

增加前置检查:

in_degree = defaultdict(int)
out_degree = defaultdict(int)
for src, dst in tickets:
    out_degree[src] += 1
    in_degree[dst] += 1

# 检查欧拉路径条件
start = "JFK"
end = [k for k in out_degree if out_degree[k]-in_degree[k]==1]
if len(end) > 1: return []

总结与学习要点

  1. 算法选择:欧拉路径问题优先考虑Hierholzer算法
  2. 优化方向:提前排序邻接表比实时排序快30%+
  3. 易错点
    • 忘记处理自循环边
    • 未考虑多解情况
    • 递归深度过大时需转迭代

参考资料

  1. 《算法导论》图论章节
  2. LeetCode官方题解
  3. Hierholzer原始论文(1873年)

”`

注:实际扩展内容时需增加更多: - 详细数学证明 - 各语言完整代码 - 性能测试数据 - 可视化图表 - 历史背景延伸等

推荐阅读:
  1. Java的应用程序服务器有哪些
  2. Java传输器的特性及用法

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java aslist

上一篇:搜索引擎优化SEO常用分析方法有哪些

下一篇:SEO指的是什么意思

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》