332. 重新安排行程

在这里插入图片描述

思路:
方法一:dfs加回溯
class Solution:
    def findItinerary(self, tickets: List[List[str]]) -> List[str]:
        from collections import defaultdict
        graph = defaultdict(list)
        for i in tickets:
            graph[i[0]].append(i[1])
            
        for i,j in graph.items():
            graph[i] = sorted(j)
            
        n = len(tickets)

        def dfs(results,result):
            if len(results) == n+1:
                return True
            
            for i in range(len(graph[result])):
                now = graph[result].pop(0)
                results.append(now)
                if dfs(results,now):
                    return True
                graph[result].append(now)
                results.pop()
            return False
            
        results = ['JFK']
        dfs(results,'JFK')
        return results
1.比较容易理解的方式:

类似大部分基本深搜,每次对当前出发点的“剩余可用目的地”循环,优先去名字值小的
但无论以递归入参还是全局变量的方式,每次进递归需层数+1,选择的ticket要暂时标为已用,即当前form-to的剩余可用次数-1
结束条件是层数达到完全遍历,若未达到又无可用目的地,说明这条路走不通了,回溯时需还原层数、可用次数

2.更烧脑但更简洁的方式:

因题目强调了“假定所有机票至少存在一种合理的行程”,所以可利用深搜一定会有结果这一点,无需任何标记、判定,仅单纯对每层进行循环及扣除
也就是每次进递归,还是对当前“剩余可用目的地”循环,但选择名字值小的进入下层时直接扣除这张机票
这样任意循环若还能进行,说明还有机票没用;反之一定是“基于已经出现的终点,自身成为更早部分的终点”
这里有点绕,举例来说第一个结束循环的一定是唯一一个这样的机场:他作为机票的终点的总次数,比作为起点的总次数多1
也就是说JFK恰好是唯一相反的机场,而其它机场作为起点和终点的总次数一定相同
所以最早结束循环的递归,一定是入参为终点时,将其加入行程数组;第二个出现的,则是之前行程中,唯一可作为终点的
以此类推……最后行程数组反向,即为答案

import collections

class Solution:
    def findItinerary(self, tickets):
        paths = collections.defaultdict(list)
        for start, tar in tickets:
            paths[start].append(tar)
        for start in paths:
            paths[start].sort(reverse=True)
        s = []

        def search(start):
            while paths[start]:
                search(paths[start].pop())
            s.append(start)

        search("JFK")
        return s[::-1]

参考:https://leetcode-cn.com/problems/reconstruct-itinerary/comments/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值