代码随想录算法训练营第三十天|回溯算法的总结、332.重新安排日程

代码随想录算法训练营第三十天|回溯算法的总结、332.重新安排日程

回溯算法的总结

  1. 回溯算法可以解决的问题
  • 组合问题:如果是一个集合求组合,需要用startIndex,如果是多个集合,且集合之间互不影响,则不用startIndex。

​ 去重问题:先给数组排序,然后用标记数组记录哪些数字已经被使用过。

  • 排列问题:每层都是从0开始搜索,用标记数组记录哪些数据已经被使用过。
  • 切割问题:切割问题难度在于怎么切割呢?终止条件是什么?如果获取切割完后的字串呢?

​ 模拟组合来切割,终止条件是已经分割成目标段数并且分割出的字串是符合条件的,获取字串 用StringBuilder记录遍历的字串,然后toString()方法转换为字符串加到结果集。

  • 子集问题:子集问题和组合问题唯一的区别就是:组合问题求的的结果在叶子节点,二子集的结果在树枝上,当然也包括叶子节点,所以代码上与组合问题的不同之处在于收集结果的位置不同。
  • 棋盘问题:N皇后,解数独等
  1. 回溯模板:
void backtracking(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}

332.重新安排日程

给你一份航线列表 tickets ,其中 tickets[i] = [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。

所有这些机票都属于一个从 JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK 开始。如果存在多种有效的行程,请你按字典排序返回最小的行程组合。

  • 例如,行程 ["JFK", "LGA"]["JFK", "LGB"] 相比就更小,排序更靠前。

假定所有机票至少存在一种合理的行程。且所有的机票 必须都用一次 且 只能用一次。

示例 1:

img

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

题解

代码:(超时代码)

class Solution {
    List<String> res=new ArrayList<>();
    List<String> path=new ArrayList<>();
    public List<String> findItinerary(List<List<String>> tickets) {
        boolean [] used=new boolean[tickets.size()];
        Collections.sort(tickets,(a,b)->a.get(1).compareTo(b.get(1)));
        path.add("JFK");
        backtracking(tickets,used);
        return res;
    }
    public boolean backtracking(List<List<String>> tickets,boolean [] used){
        //终止条件 机场数比航班数多1
        if(path.size()==tickets.size()+1){
            res=path;
            return true;
        }
        //for循环
        for(int i=0;i<tickets.size();i++){
            if(!used[i] && tickets.get(i).get(0).equals(path.getLast())){
                path.add(tickets.get(i).get(1));
                used[i]=true;

                if(backtracking(tickets,used)){
                    return true;
                }
                used[i]=false;
                path.removeLast();
            }
        }
        return false;
    }
}

优化代码

要优化这段代码以避免超时,你可以考虑以下几点:

  • 使用 HashMap 代替 ArrayList 来存储机场及其对应的航班信息。 这样可以提高查找速度,避免每次都遍历整个列表来查找目标机场的航班。
  • 采用深度优先搜索(DFS)来遍历航班。 这样可以尽早找到满足条件的路径,避免不必要的遍历。

​ 在 DFS 中使用递归或栈来实现。 递归比较直观,而栈则可以手动控制搜索顺序,适合对搜索顺序有要求的情况。在找到第一个满足条件的路径后就立即返回。 不必继续搜索其他可能的路径。

有效代码

class Solution {
    List<String> res = new ArrayList<>();
    Map<String, PriorityQueue<String>> flights = new HashMap<>();

    public List<String> findItinerary(List<List<String>> tickets) {
        // 构建航班信息
        for (List<String> ticket : tickets) {
            flights.computeIfAbsent(ticket.get(0), k -> new PriorityQueue<>()).add(ticket.get(1));
        }

        // 从起始机场开始 DFS
        dfs("JFK");
        return res;
    }

    private void dfs(String airport) {
        // 检查当前机场是否存在航班
        PriorityQueue<String> destinations = flights.getOrDefault(airport, new PriorityQueue<>());
        while (!destinations.isEmpty()) {
            dfs(destinations.poll());
        }
        // 将当前机场加入结果集
        res.add(0, airport);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值