重新安排行程问题

问题描述

我一开始的做法:

class Solution {
    ArrayList<String> result = new ArrayList<>();
    ArrayList<String> path = new ArrayList<>();
    boolean[] used;
    
    public List<String> findItinerary(List<List<String>> tickets) {
        if (tickets.size() == 0) {
            return result;
        }
        used = new boolean[tickets.size()]; 

        //为空时添加第一个元素并开始回溯
        for (int i = 0; i < tickets.size(); i++) {
            if (tickets.get(i).get(0).equals("JFK")) {
                path.add(tickets.get(i).get(0));
                path.add(tickets.get(i).get(1));
                used[i] = true;
                backtracing(tickets);
                used[i] = false;
                path.removeLast();
                path.removeLast();
            } 
        }
        return result;
    }

    public void backtracing(List<List<String>> tickets) {
        if (path.size() == tickets.size() + 1) {
            //System.out.println(path.toString());
            if (result.isEmpty()) {
                result = new ArrayList<>(path);
            } else{
                for (int i = 0; i < path.size(); i++) {
                    if (path.get(i).compareTo(result.get(i)) < 0) {
                        result = new ArrayList<>(path);
                        break;
                    }
                    if (path.get(i).compareTo(result.get(i)) > 0) {
                        break;
                    }
                }
            }
        }

        int addIndex = -1;

        //一次添加一个元素
        for (int i = 0; i < tickets.size(); i++) {
            if (used[i]) {
                continue;
            }
            if (tickets.get(i).get(0).equals(path.get(path.size() - 1))) {
                path.add(tickets.get(i).get(1));
                used[i] = true;
                backtracing(tickets);
                used[i] = false;
                path.removeLast();
            }
        }    
    }
}

可能能得到正确的结果,但是会超时,因为每次都是一个完全的遍历,O(n^tickets.size())的时间复杂度

改进的地方:对机票的信息进行预先的排序,同时用哈希表存储,这样可以降低搜索的复杂度从而提高效率

使用回溯的思想:

一个需要注意的地方:这里的回溯返回值为boolean

**基于list的回溯:**预先对tickets进行排序,然后就是简单的回溯,但是在最新的测试样例里,还是会超时

class Solution {
    LinkedList<String> result = new LinkedList<>();
    LinkedList<String> path = new LinkedList<>();
    boolean[] used;
    
    public List<String> findItinerary(List<List<String>> tickets) {
        Collections.sort(tickets, (a, b) -> a.get(1).compareTo(b.get(1)));
        used = new boolean[tickets.size()];
        path.add("JFK");
        backtracing((ArrayList)tickets);
        return result;
    }

    public boolean backtracing(ArrayList<List<String>> tickets) {
        if (path.size() == tickets.size() + 1) {
            result = new LinkedList<>(path);
            return true;
        }

        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 (backtracing(tickets)) {
                    return true;
                }

                //回溯
                used[i] = false;
                path.removeLast();
            }
        }
        return false;
    }
    
}

基于map的回溯:

用treemap来存储同一个起始站的机票,对终点进行排序,这样找到的第一组路径就是最终需要的序列最小的路径

class Solution {
    

    Map<String, Map<String, Integer>> record;
    LinkedList<String> res;
    public List<String> findItinerary(List<List<String>> tickets) {
        record = new HashMap<>();
        res = new LinkedList<>();
        //初始化record
        for (List<String> ticket : tickets) {
            //temp存的<目的地,票数>
            Map<String, Integer> temp;
            String startSite = ticket.get(0); //当前机票出发地
            String destination = ticket.get(1); //当前机票终点站
            if (record.containsKey(startSite)) {
                temp = record.get(startSite);
                temp.put(destination, temp.getOrDefault(destination, 0) + 1);
            } else {
                temp = new TreeMap<>();
                temp.put(destination, 1);
            }
            record.put(startSite, temp);
        }
        res.add("JFK");
        backtracing(tickets);
        return res;
    }

    public boolean backtracing(List<List<String>> tickets) {
        if (res.size() == tickets.size() + 1) {
            return true;
        }

        if (record.containsKey(res.getLast())) {
            for (Map.Entry<String, Integer> entry : record.get(res.getLast()).entrySet()) {
                int count = entry.getValue();
                if (count > 0) {
                    res.add(entry.getKey());
                    entry.setValue(count - 1);
                    if(backtracing(tickets)) {
                        return true;
                    }

                    entry.setValue(count);
                    res.removeLast();
                }
            }
        }
        return false;
    }

    
}

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值