题目:
思路:
有向图的深度优先搜索。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); // 可能会将多个路线堆在一起(后序遍历,顺序是反的)
}
};