332 重新安排行程(dfs)

1. 问题描述:

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

说明:

如果存在多种有效的行程,你可以按字符自然排序返回最小的行程组合。例如,行程 ["JFK", "LGA"] 与 ["JFK", "LGB"] 相比就更小,排序更靠前
所有的机场都用三个大写字母表示(机场代码)。
假定所有机票至少存在一种合理的行程。
示例 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"]。但是它自然排序更大更靠后。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reconstruct-itinerary

2. 思路分析:

① 看到题目会想到使用普通模拟的思路可以解决,因为我们可以把这些字符串放到map中,这样在取出字符串的话就会很方便,因为题目中要求字典序最小的,所以可以对map中映射的值进行排序,然后模拟整个过程即可,但是这个想法还是存在一定漏洞的,因为有可能字典序较小的是不合理的行程,比如像这个数据[["JFK","KUL"],["JFK","NRT"],["NRT","JFK"]]字典序较小的起点为[["JFK","KUL"]但是这个并不是合理的,所以不能够使用这样的方法来解决

② 所以首先需要解决一个问题是map中的数据映射,其实放到map中比较简单,关键是对map中的字符串类型进行排序,一开始的时候使用的是Deque来放字符串但是发现没有对Deque的String类型排序的方法,后面在题解中发现可以使用List来放置字符串,因为使用List类型可以对List的String类型使用java 8语法来进行排序,先是要取出map的值然后使用forEach方法对其遍历,里面传入排序的对象,后面是对象中的什么方法来进行排序

③ 因为存在不确定性的尝试,所以可以使用dfs来解决,使用dfs来解决的话还有一个特点是能够走完所有的行程并且还有一个优点是可以利用dfs层层返回的这个特点来添加终点,因为在①中说到字典序最小的行程并不一定是合理的所以这个时候不能够在递归前来添加终点否则有的结果是错误的,比如像[["JFK","KUL"],["JFK","NRT"],["NRT","JFK"]]这个数据,而在dfs调用之后添加终点恰恰可以解决这个问题,因为每一次递归调用都会先把合理的行程先添加上去,比如上面这个数据一开始递归调用先是[["JFK","KUL"],这个起点发现走不下去了,尝试另外一个起点["JFK","NRT"],发现存在另外一条可行的路径,最终在返回的时候先将后面这路径先添加到结果中JFK, NRT然后再添加上一开始的KUL这样的结果才是正确的,通常我们在写dfs代码的时候可能根据具体的情况在递归之前处理或者是递归调用之后处理来获取某些值,这个是我们在使用dfs解决问题的时候需要处理的点和学会的一个点

3. 代码如下:

import java.util.*;
class Solution {
    List<String> res = new ArrayList<>();
    public List<String> findItinerary(List<List<String>> tickets) {
        Map<String, List<String>> map = new HashMap();
        for (List<String> list : tickets){
            /*使用getOrDefault方法很方便因为假如之前没有当前的键那么就新建假如有就获取之前的值*/
            List<String> li = map.getOrDefault(list.get(0), new ArrayList<String>());
            li.add(list.get(1));
            map.put(list.get(0), li);
        }
        /*使用java8的语法进行排序*/
        map.values().forEach(x -> x.sort(String::compareTo));
        dfs(tickets, "JFK", map);
        return res;
    }

    private void dfs(List<List<String>> tickets, String start, Map<String, List<String>> map) {
        List<String> list = map.get(start);
        while (list != null && list.size() > 0){
            dfs(tickets, list.remove(0), map);
        }
        /*返回的时候添加终点: 这一句代码是核心因为正着插的时候会导致: ["JFK","KUL","NRT","JFK"]数据出现错误*/
        res.add(0, start);
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
思路: 1. 先建立一个图,用邻接表表示。遍历tickets数组,以出发城市为键,以到达城市为值,将所有相同出发城市的到达城市加入到对应的键的值列表。 2. 对每个出发城市的到达城市列表进行排序,保证按字母顺序进行访问。 3. 从"JFK"出发,进行深度优先遍历。如果当前城市的到达城市列表不为空,则按顺序访问列表中的城市,并将访问过的城市从列表中删除。 4. 如果当前城市没有到达城市或者到达城市已经全部被访问过了,则将当前城市加入结果列表的头部。 5. 最后得到的结果列表,逆序输出即可得到答案。 代码实现如下: ```python from collections import defaultdict def findItinerary(tickets): # 用于保存图 graph = defaultdict(list) # 将tickets中的数据存入图 for ticket in tickets: src, dst = ticket graph[src].append(dst) # 按照字母顺序对到达城市进行排序 for src in graph: graph[src].sort() def dfs(city): # 当前城市的到达城市列表 destinations = graph[city] while destinations: # 递归遍历下一个城市 dfs(destinations.pop(0)) # 将当前城市加入结果列表 result.insert(0, city) # 结果列表 result = [] dfs("JFK") return result # 测试 tickets = [["MUC","LHR"],["JFK","MUC"],["SFO","SJC"],["LHR","SFO"]] print(findItinerary(tickets)) # 输出:['JFK', 'MUC', 'LHR', 'SFO', 'SJC'] ``` 复杂度分析: - 时间复杂度:建立图的过程需要遍历tickets数组,时间复杂度为O(n),其中n为数组的长度。遍历图的过程中,所有的边都会被访问一次,时间复杂度为O(m),其中m为图中的边数。因此,总的时间复杂度为O(n+m)。 - 空间复杂度:使用了一个字典来保存图,空间复杂度为O(m),其中m为图中的边数。递归调用的深度为图中的边数+1,空间复杂度为O(m+1)。最后返回的结果列表的空间复杂度为O(n),其中n为结果列表的长度。因此,总的空间复杂度为O(m+n)。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值