代码随想录:回溯19

332.重新安排行程

题目

给你一份航线列表 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"] ,但是它字典排序更大更靠后。

代码

class Solution {
    //用深度优先搜索:dfs+map+优先队列
    Map<String,PriorityQueue<String>> map = new HashMap<>();
    List<String> res = new LinkedList<>();
    public List<String> findItinerary(List<List<String>> tickets) {
        //把tickets转为map,key是出发点,value是所有到达点的优先队列(按字典升序)
        for(List<String> ticket : tickets){
            String from = ticket.get(0);  //出发点 
            String to = ticket.get(1);   //到达点
            //from不在map,new一个pq
            if(!map.containsKey(from)){
                PriorityQueue<String> pq = new PriorityQueue<>();
                map.put(from,pq);
            }
            //把到达点加入from的pq队列中
            map.get(from).add(to);
        }
        dfs("JFK");  //从JFK开始深度优先
        return res;
    }
    public void dfs(String from){
        PriorityQueue<String> pq = map.get(from);  //获取JFK的到达pq队列
        while(pq != null &&!pq.isEmpty()){ 
            String to = pq.poll();  //从优先队列中取首元素,字典序最小的,poll保证了所有机票只用一次
            dfs(to);  //从to继续深度优先
        }
        res.addFirst(from);  //把深度优先的元素一个个加到链表前面
    }
}

总结

        优先队列可以保证让我们找到字典序最小的路径。

        这道题用回溯操作嵌套的map,代码会很难写,而且容易超时,用深度优先+map+优先队列是最好理解的。以下图为例。

        map={ JFK,{ATL,SFO}, ATL,{JFK,SFO}, SFO,{ATL} }

        首先,从JFK开始获取到它的优先队列pq={ATL,SFO},ATL是队首元素,说明ATL是JFK的字典序最近到达点,因此路径JFK-ATL。此时JFK的pq={SFO}

        然后,从ATL开始获取它的优先队列pq={JFK,SFO},JFK是队首元素,说明JFK是ATL的字典序最近到达点,因此路径JFK-ATL-JFK。此时ATL的pq={SFO}

        然后,从JFK开始获取它的优先队列pq={SFO},SFO是队首元素,说明SFO是JFK的字典序最近到达点,因此路径JFK-ATL-JFK-SFO。此时JFK的pq={null}

        然后,从SFO开始获取它的优先队列pq={ATL},ATL是队首元素,说明ATL是STO的字典序最近到达点,因此路径JFK-ATL-JFK-SFO-ATL。此时SFO的pq={null}

        然后,从ATL开始获取它的优先队列pq={SFO},SFO是队首元素,说明SFO是ATL的字典序最近到达点,因此路径JFK-ATL-JFK-SFO-ATL-SFO。此时ATL的pq={null}

        然后,从SFO开始获取它的优先队列pq={},此时pq为空,路径结束。

        最后就是按DFS的顺序把每一个位置点加入链表,因为是深度优先搜索,所以最后递归到的ATL位置放在后边,最早递归到的JFK位置放在最前面。

        搞定!

        

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

守岁白驹hh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值