Я решаю вопрос по Leetcode: https://leetcode.com/problems/reconstruct-itinerary/description/. Вопрос в том:
Given a list of airline tickets represented by pairs of departure and
arrival airports [from, to], reconstruct the itinerary in order. All of
the tickets belong to a man who departs from JFK. Thus, the itinerary
must begin with JFK.
Например, если tickets = [["MUC", "LHR"], ["JFK", "MUC"], ["SFO", "SJC"], ["LHR", "SFO"]]
Выход должен быть: ["JFK", "MUC", "LHR", "SFO", "SJC"]
,
Я написал следующий код, который (по понятным причинам) ломается на входе [["JFK","KUL"],["JFK","NRT"],["NRT","JFK"]]
потому что, согласно моему коду, узел «NRT» остается не посещенным:
class Solution {
public:
vector<string> findItinerary(vector<pair<string, string>> tickets) {
if(tickets.empty()) return vector<string>();
vector<string> result;
unordered_map<string, multiset<string>> itinerary;
for(auto& each : tickets)
itinerary[each.first].insert(each.second);
stack<string> myStack;
myStack.push("JFK");
while(!myStack.empty()) {
string topVal=myStack.top();
result.push_back(topVal);
myStack.pop();
if(!itinerary[topVal].empty()) {
myStack.push(*itinerary[topVal].begin());
itinerary[topVal].erase(itinerary[topVal].begin());
}
}
return result;
}
};
Чтобы преодолеть это, одно из предложенных решений предлагает это небольшое изменение:
class Solution {
public:
vector<string> findItinerary(vector<pair<string, string>> tickets) {
if(tickets.empty()) return vector<string>();
vector<string> result;
unordered_map<string, multiset<string>> itinerary;
for(auto& each : tickets)
itinerary[each.first].insert(each.second);
stack<string> myStack;
myStack.push("JFK");
while(!myStack.empty()) {
string topVal=myStack.top();
if(itinerary[topVal].empty()) { //--->this if condition
result.push_back(topVal);
myStack.pop();
}
else {
myStack.push(*itinerary[topVal].begin());
itinerary[topVal].erase(itinerary[topVal].begin());
}
}
reverse(result.begin(), result.end());
return result;
}
};
Теперь я работал над этим кодом на примере [["JFK","KUL"],["JFK","NRT"],["NRT","JFK"]]
и увидел, как он вставляет значения в result
вектор в обратном порядке; но я не понимаю интуиция за этим условием:
Каким образом извлечение из стека только при пустом наборе гарантирует, что этот контрольный пример позаботится?
Проблема заключается в том, чтобы найти Эйлерова тропа в ориентированном графе, где каждая пара [от, до] представляет ребро.
В ответе с голосованием используется алгоритм, который называется Алгоритм Гирхольцера (Алгоритм Гирхольцера изначально используется для поиска Эйлера цикл, но это легко пересмотреть для Эйлера дорожка). Как правило, это
продолжайте следовать неиспользованным краям и удаляя их, пока мы не застрянем. Как только мы застряли, мы возвращаемся к ближайшей вершине в нашем текущем пути, которая имеет неиспользуемые ребра, и мы повторяем процесс, пока все ребра не будут использованы.
Подчеркнутая часть — это разница между вашим решением и решением, получившим голос.
Постскриптум Хотя алгоритм прост, доказательство правильности не так тривиально. Если вы заинтересованы в этом, вы можете искать его в Интернете.
После посещения to
город удаляется, что фактически означает, что to
город как промежуточный from
город был посещен, и нет необходимости рассматривать его в следующий раз from
город посещают, иначе это будет бесконечный цикл без остановки.
Таким образом if
заявление, где проверка происходит ли все to
города для from
город уже побывал. Это в значительной степени похоже на посещаемый массив, отслеживающий все города, посещенные до сих пор.