Skip to content
本页目录

0332-重新安排行程

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

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

提示:

  • 1 <= tickets.length <= 300
  • tickets[i].length == 2
  • fromi.length == 3
  • toi.length == 3
  • fromi 和 toi 由大写英文字母组成
  • fromi != toi

思路 : 回溯会超时

  • 先排序,保证字典顺序的再前面
  • 回溯法,探测可以使用的线路,设置 used = true
  • 当全部线路轮询完毕后,得到结果

参考代码

csharp
public class Solution {
	private List<string> result = new List<string>();
	private bool[] used;

	private void dfs(IList<IList<string>> tickets, int index, string last,List<int> list){
		if(index == tickets.Count){
			//输出结果
            result.Clear();
			for(int i=0; i<list.Count; i++){
				result.Add(tickets[list[i]][0]);
			}
            result.Add(tickets[list[list.Count-1]][1]);
			return;
		}

		for(int i=0; i<tickets.Count; i++){
			if(tickets[i][0] == last && !used[i]){
				used[i] = true;
				list.Add(i);
				dfs(tickets,index+1,tickets[i][1],list);
				list.RemoveAt(list.Count - 1);
				used[i] = false;
			}			
		}	
	}

    public IList<string> FindItinerary(IList<IList<string>> tickets) {
        tickets = tickets.OrderByDescending(x => x.ElementAt(1)).ToList();
    	List<int> list = new List<int>();
    	used = new bool[tickets.Count];
    	dfs(tickets,0,"JFK",list);
    	return result;
    }
}

思路2:官方题解

  • 定义一个数组,记录每一次选择的 索引位置
  • 找 from 在tickets 子集,从 0 索引开始找,找到的话:tickets 减去这个元素,list 增加一个元素
  • 当 一次新的 from 找不到 tickets 子集时,说明前面选择有误,回退一步
  • 当 一次新的 from 找出来的 tickets 子集个数 已经都跑过了,也没有办法找到解决方案,同样回退一步
  • 注意:回退一步的操作是,tickets 追加回去,list 减去一个

https://leetcode.cn/problems/reconstruct-itinerary/solution/zhong-xin-an-pai-xing-cheng-hui-su-by-a-liang-3a/

csharp
public class Solution {
    public IList<string> FindItinerary(IList<IList<string>> tickets) {
        IList<string> list = new List<string>();
        string from = "JFK";
        list.Add(from);
        int len = tickets.Count + 1;
        int[] pa = new int[len];
        int pos = 0;
        while (list.Count < len)
        {
            IList<IList<string>> curList = tickets.Where(x => x.ElementAt(0) == from).OrderBy(x => x.ElementAt(1)).ToList();
            if (curList.Count== 0 || curList.Count == pa[pos])
            {
                from = list.ElementAt(list.Count-2);
                //tickets 加回去
                IList<string> reback = new List<string>();
                reback.Add(from);
                reback.Add(list.ElementAt(list.Count - 1));
                tickets.Add(reback);
                // list 减掉
                list.RemoveAt(list.Count - 1);

                if (curList.Count == pa[pos])
                {
                    pa[pos] = 0;
                }

                pos--;
                continue;
            }
            from = curList.ElementAt(pa[pos]).ElementAt(1);
            //tickets 减
            tickets.Remove(curList.ElementAt(pa[pos]));
            //list 加
            list.Add(from);
            pa[pos]++;
            pos++;
        }
        return list;
    }
}

复习:欧拉回路 20220713

  1. 用哈希表和list储存图的关系,因为满足条件的需要是字典序,所以 list 按照自增排序
  2. 从 JFK 出发之后,dfs遍历能到达的点,然后到达之后,就拆掉这一边。 因为这是半欧拉图,所以死胡同必然是第一个到达的并且递归回来的,把它加入到 result 里面,最后按照 result 的反序输出
csharp
public class Solution {

    Dictionary<string,List<string>> dict = new Dictionary<string,List<string>>();
    List<string> result = new List<string>();

    private void dfs(string source){
        if(dict.ContainsKey(source) &&  dict[source].Count > 0){
            while(dict[source].Count > 0){ //这里不能用 for 循环,因为 remove 的时候 count 会改变
                string target = dict[source][0]; //每次取第一个
                dict[source].Remove(target);                
                dfs(target);
            }
        }
        result.Add(source);
    }

    public IList<string> FindItinerary(IList<IList<string>> tickets) {
        //储存数据到图
        for(int i=0; i<tickets.Count; i++){
            string source = tickets[i][0];
            string target = tickets[i][1];
            if(!dict.ContainsKey(source)){
                dict.Add(source,new List<string>());
            }
            // target 不需要加入,没有target起点的地方, dfs会跳过
            // if(!dict.ContainsKey(target)){
            //     dict.Add(target,new List<string>());
            // }
            dict[source].Add(target);
        }
        //排序元素

        foreach(string key in dict.Keys){
            if(dict[key].Count > 0){
                dict[key].Sort((a,b)=>{
                    return a.CompareTo(b);
                });
            }
        }

        dfs("JFK");
        result.Reverse();
        return result;
    }
}

Released under the MIT License.