回溯 Leetcode 332 重新安排行程

文章讨论了在LeetCode题目中,通过回溯策略和机票排序,找到从JFK出发并按字典序最小的行程组合。提供两种方法:使用vector的Solution和map存储的优化版本。
摘要由CSDN通过智能技术生成

重新安排行程

Leetcode 332

学习记录自代码随想录

给你一份航线列表 tickets ,其中 tickets[i] = [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。
所有这些机票都属于一个从 JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK 开始。如果存在多种有效的行程,请你按字典排序返回最小的行程组合。
例如,行程 [“JFK”, “LGA”] 与 [“JFK”, “LGB”] 相比就更小,排序更靠前。
假定所有机票至少存在一种合理的行程。且所有的机票 必须都用一次 且 只能用一次。

输入:tickets = [[“MUC”,“LHR”],[“JFK”,“MUC”],[“SFO”,“SJC”],[“LHR”,“SFO”]]
输出:[“JFK”,“MUC”,“LHR”,“SFO”,“SJC”]
输入:tickets = [[“JFK”,“SFO”],[“JFK”,“ATL”],[“SFO”,“ATL”],[“ATL”,“JFK”],[“ATL”,“SFO”]]
输出:[“JFK”,“ATL”,“JFK”,“SFO”,“ATL”,“SFO”]
解释:另一种有效的行程是 [“JFK”,“SFO”,“ATL”,“JFK”,“ATL”,“SFO”] ,但是它字典排序更大更靠后。

要点:1.回溯模板上修改一些判断条件;
2.需要开始对车票排序,之后排过序后只要找到一个方案就是所需的字母排序最小的方案;
3.检查重复的车票,有的车票会重复;
4.检查使用过的车票以及车票开头是否等于上次末尾;

方法一:

class Solution {
private:
    // vector<string> path = {"JFK"};
    string start = "JFK";
    vector<vector<string>> result;

    void backtracking(vector<vector<string>>& tickets, vector<int> used, vector<string> path){
        if(path.size() == tickets.size() + 1){
            result.push_back(path);
            return;
        }

        // start = path.back();
        for(int i = 0; i < tickets.size(); i++){
            // 已经对车票开始排过序了,所以只要找到一个方案就是所需的字母排序最小的方案
            if(result.size() > 0) break;
            // 检查重复的车票,有的车票会重复
            if (i > 0 && !used[i - 1] && tickets[i][0] == tickets[i - 1][0] && tickets[i][1] == tickets[i - 1][1]) {
                continue;
            }
            // 检查使用过的车票以及车票开头是否等于上次末尾
            if(used[i] == 1 || tickets[i][0] != start){
                continue;
            }
            start = tickets[i][1];
            used[i] = 1;
            path.push_back(tickets[i][1]);
            backtracking(tickets, used, path);
            path.pop_back();
            start = path.back();
            used[i] = 0;
        }

    }
public:
    vector<string> findItinerary(vector<vector<string>>& tickets){
        // path.clear();

        sort(tickets.begin(), tickets.end());
        vector<string> path = {"JFK"};
        vector<int> used(tickets.size(), 0);
        backtracking(tickets, used, path);
        // sort(result.begin(), result.end());

        return result[0];
    }
};

方法二:使用map存储机票路径

在这里插入图片描述

//使用map存储
class Solution{
private:
    // 出发机场,<到达机场,标记机场是否使用过>
    unordered_map<string, map<string, int>> targets;
    // 注意此处result需要引用,不然输入的result只是为形参,不改变原来的result
    bool backtracking(vector<string>& result, vector<vector<string>>& tickets){
        if(result.size() == tickets.size() + 1){
            return true;
        }

        // target需要引用以对应更改targets, const防止更改
        // for(auto& target : targets[result.back()]){
        for(pair<const string, int>& target : targets[result.back()]){
            if(target.second > 0){
                result.push_back(target.first);
                target.second--;
                if(backtracking(result, tickets)) return true;  // 这样一找到结果就能返回
                result.pop_back();  // 回溯
                target.second++;  // 回溯
            }
        }

        return false;
    }

public:
    vector<string> findItinerary(vector<vector<string>>& tickets){
        targets.clear();

        // 记录映射关系,map是有序的,存储结果自动会排序,1代表没去过,0代表去过
        for(const vector<string>& vec : tickets){
            targets[vec[0]][vec[1]]++;
        }
        vector<string> result;
        result.push_back("JFK");
        backtracking(result, tickets);

        return result;
    }
};
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值