(dfs)LeetCode -- 332.重新安排行程(Python)

题目

https://leetcode-cn.com/problems/reconstruct-itinerary/

给定一个机票的字符串二维数组 [from, to],子数组中的两个成员分别表示飞机出发和降落的机场地点,对该行程进行重新规划排序。所有这些机票都属于一个从 JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK 开始。

提示:

  1. 如果存在多种有效的行程,请你按字符自然排序返回最小的行程组合。例如,行程 [“JFK”, “LGA”] 与 [“JFK”, “LGB”] 相比就更小,排序更靠前

  2. 所有的机场都用三个大写字母表示(机场代码)。

  3. 假定所有机票至少存在一种合理的行程。

  4. 所有的机票必须都用一次 且 只能用一次。

示例1:

输入:[["MUC", "LHR"], ["JFK", "MUC"], ["SFO", "SJC"], ["LHR", "SFO"]]
输出:["JFK", "MUC", "LHR", "SFO", "SJC"]

示例2:

输入:[["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]]
输出:["JFK","ATL","JFK","SFO","ATL","SFO"]
解释:另一种有效的行程是 ["JFK","SFO","ATL","JFK","ATL","SFO"]。但是它自然排序更大更靠后。

思路

1. 因题目强调了“假定所有机票至少存在一种合理的行程”,所以可利用深搜一定会有结果这一点,无需任何标记、判定,仅单纯对每层进行循环及扣除
2. 这是一个有向图的题目,有图就先建立一个由每个始发地为键,目的地为值组成的列表字典,题目要求“请按字符自然排序返回最小的形成组合”,所以对列表进行倒序排序
3. 准备深搜的堆栈,用于回溯
4. 并且所有地点都要经过,在规划行程中,当某个地点 f 不能去到下一个地方,且还没经过所有地点,就把 f 记录在行程最后,然后回溯到上一个地点进行搜索

代码提交

from typing import List
import collections


class Solution:
    def findItinerary(self, tickets: List[List[str]]) -> List[str]:
        paths = collections.defaultdict(list) # 由每个始发地为键,目的地为值组成的列表字典
        for f, t in tickets: # f, t 分别为from, to,表示机票的始发地和目的地
            paths[f].append(t)
        for f in paths:
            paths[f].sort(reverse=True)
        res = []
        f_stack = ['JFK'] # dfs所用的堆栈,用于回溯
        while f_stack:
            f = f_stack[-1]
            if paths[f]:
                f_stack.append(paths[f].pop()) # 把 t 弹出,并添加到深搜堆栈中,把 t 作为 f 再进行深搜
            else:
                res.append(f) # 把没有 t 的 f 添加到结果列表
                f_stack.pop() # 把没有 t 的 f 从深搜堆栈中弹出
        return res[::-1] # 将结果列表倒序输出


S = Solution()
tickets = [["MUC", "LHR"], ["JFK", "MUC"], ["SFO", "SJC"], ["LHR", "SFO"]]
ans = S.findItinerary(tickets)
print(ans)

执行用时:44 ms, 在所有 Python3 提交中击败了95.05%的用户
内存消耗:13.8 MB, 在所有 Python3 提交中击败了96.24%的用户

拓展

  • 深度优先搜索 dfs = 堆栈、入栈、出栈
  • 广度优先搜索 bfs = 队列、入队、出队
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值