The "Destination City" problem asks you to determine the final destination city given a list of direct paths between cities. Each path is represented as a pair [cityA, cityB]
, meaning there is a direct path from cityA
to cityB
. The list forms a sequence of connected cities, and it is guaranteed that the paths form a single line (no cycles, no branches).
paths
where each element is a pair of strings: [fromCity, toCity]
.Key constraints:
The problem is about tracing a path through a series of cities and finding the city where the journey ends. If you imagine the cities as nodes and the paths as arrows, the destination city is the one that has arrows pointing to it, but never has an arrow pointing from it.
The brute-force approach might be to simulate the journey by following the paths, but that could be inefficient. Instead, we can approach the problem by analyzing the properties of the input:
This leads us to think about using sets or hash maps to efficiently check which cities are only destinations. This is much faster than following the paths one-by-one.
Let's break down the steps for an efficient solution:
fromCity
of each path to a set. This set will contain all the cities that are used as a starting point.toCity
. If a toCity
is not in the set of starting cities, it must be the destination city.We use a set for starting cities because lookups in a set are O(1), making the algorithm efficient even for large input sizes.
Suppose the input is:
paths = [["London", "New York"], ["New York", "Lima"], ["Lima", "Sao Paulo"]]
The function returns "Sao Paulo"
.
This efficiency is achieved by using a set for constant-time lookups.
The "Destination City" problem is best solved by recognizing that the destination is the only city never used as a starting point. By collecting all starting cities in a set, we can quickly check which city is the unique destination. This approach is both simple and efficient, making excellent use of data structures for fast lookups. The key insight is that the problem reduces to set membership, not path traversal.
class Solution:
def destCity(self, paths):
starts = set()
for path in paths:
starts.add(path[0])
for path in paths:
if path[1] not in starts:
return path[1]
class Solution {
public:
string destCity(vector<vector<string>>& paths) {
unordered_set<string> starts;
for (const auto& path : paths) {
starts.insert(path[0]);
}
for (const auto& path : paths) {
if (starts.find(path[1]) == starts.end()) {
return path[1];
}
}
return "";
}
};
class Solution {
public String destCity(List<List<String>> paths) {
Set<String> starts = new HashSet<>();
for (List<String> path : paths) {
starts.add(path.get(0));
}
for (List<String> path : paths) {
if (!starts.contains(path.get(1))) {
return path.get(1);
}
}
return "";
}
}
var destCity = function(paths) {
const starts = new Set();
for (const path of paths) {
starts.add(path[0]);
}
for (const path of paths) {
if (!starts.has(path[1])) {
return path[1];
}
}
};