【leetcode】332. Reconstruct Itinerary

题目:
在这里插入图片描述


思路:
有向图的深度优先搜索。tickets里实际上保存的是图的有向边。我用unordered_map保存每个from节点(出发地)到其所有邻接to节点(目的地,用一个链表将所有邻接to节点按照字符串从小到大的顺序串起来)的映射关系。每次深度优先遍历邻接点时,都临时将节点从对应链表中删除掉,继续进行更深度的递归。如果能成功,即所有地点都串起来了(总数为边的数量加1),则ok;如果不成功,则将删除的节点再添加回去,继续尝试下一个邻接点。如此往复,直到成功。


代码实现:
代码搞了好几个小时,真就一点一点debug才通过的,快吐了。

struct node{
    string *val;
    node *next;
    node(){
        this->next = nullptr;
    }
    node(string &val){
        this->val = &val;
        this->next = nullptr;
    }
    
};
class Solution {
public:
    
    bool f(unordered_map<string, node*>& my_map, string cur, int remain, vector<string>& ans) {
        if (remain == 0) {
            return true;
        }

        node* p = new node();
        if (my_map.find(cur) == my_map.end()) {
            return false;
        }

        p->next = my_map[cur];
        if (p->next == nullptr) {
            return false;
        }

        node* t = p->next;
        my_map[cur] = my_map[cur]->next;
        ans.push_back(*(t->val));
        if (f(my_map, *(t->val), remain - 1, ans)) {
            return true;
        }
        ans.pop_back();
        t->next = my_map[cur];
        my_map[cur] = t;
        p = t;

        while (p->next) {
            node* t = p->next;
            p->next = p->next->next;
            ans.push_back(*(t->val));
            if (f(my_map, *(t->val), remain - 1, ans)) {
                return true;
            }
            ans.pop_back();
            t->next = p->next;
            p->next = t;
            p = t;
        }

        return false;
    }

    vector<string> findItinerary(vector<vector<string>>& tickets) {
        if (tickets.size() <= 0) {
            return {};
        }
        int len = tickets.size();
        unordered_map<string, node*> my_map;
        vector<string> ans;
        int remain = tickets.size() + 1;

        for (int i = 0; i < len; ++i) {
            string& from = tickets[i][0];
            string& to = tickets[i][1];
            node* to_node = new node(to);
            if (my_map.find(from) == my_map.end()) {
                my_map[from] = to_node;
            }
            else {
                node* p = my_map[from];
                if (*(to_node->val) < *(p->val)) {
                    to_node->next = p;
                    my_map[from] = to_node;
                }
                else {
                    while (p->next && *(to_node->val) > * (p->next->val)) {
                        p = p->next;
                    }
                    to_node->next = p->next;
                    p->next = to_node;
                }

            }
        }

        ans.push_back("JFK");
        f(my_map, ans[0], remain - 1, ans);

        return ans;
    }
};

discuss:

// 思路:将所有[from,to]保存到map<string, multiset<string>>中,然后递归遍历即可。
class Solution {
public:
    map<string, multiset<string>> targets; // 可能会出现重复[from, to],并可能多次用到ta。multiset应该是按字母顺序自动排序了
    vector<string> route;
    
    vector<string> findItinerary(vector<vector<string>>& tickets) {
        for (auto ticket : tickets)
            targets[ticket[0]].insert(ticket[1]); // 把所有[from, to]都存放到map<string, multiset<string>>中
        visit("JFK");
        return vector<string>(route.rbegin(), route.rend());
    }
    
    void visit(string airport){
        while (targets[airport].size()){ // 遍历airport所指向的那个multiset(存放着所有目的地)
            string next = *targets[airport].begin(); // 从multiset读取第一个目的地
            targets[airport].erase(targets[airport].begin()); // 读完后将其从multiset中删除
            visit(next); // 递归读取
        }
        route.push_back(airport); // 可能会将多个路线堆在一起(后序遍历,顺序是反的)
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值