Find the City With the Smallest Number of Neighbors at a Threshold Distance
MedPrompt
There are n cities numbered from 0 to n-1. Given the array edges where edges[i] = [fromi, toi, weighti] represents a bidirectional and weighted edge between cities fromi and toi, and given the integer distanceThreshold.
Return the city with the smallest number of cities that are reachable through some path and whose distance is at most distanceThreshold, If there are multiple such cities, return the city with the greatest number.
Notice that the distance of a path connecting cities i and j is equal to the sum of the edges' weights along that path.
Example 1:

Input: n = 4, edges = [[0,1,3],[1,2,1],[1,3,4],[2,3,1]], distanceThreshold = 4
Output: 3
Explanation: The figure above describes the graph.
The neighboring cities at a distanceThreshold = 4 for each city are:
City 0 -> [City 1, City 2]
City 1 -> [City 0, City 2, City 3]
City 2 -> [City 0, City 1, City 3]
City 3 -> [City 1, City 2]
Cities 0 and 3 have 2 neighboring cities at a distanceThreshold = 4, but we have to return city 3 since it has the greatest number.Example 2:

Input: n = 5, edges = [[0,1,2],[0,4,8],[1,2,3],[1,4,2],[2,3,1],[3,4,1]], distanceThreshold = 2
Output: 0
Explanation: The figure above describes the graph.
The neighboring cities at a distanceThreshold = 2 for each city are:
City 0 -> [City 1]
City 1 -> [City 0, City 4]
City 2 -> [City 3, City 4]
City 3 -> [City 2, City 4]
City 4 -> [City 1, City 2, City 3]
The city 0 has 1 neighboring city at a distanceThreshold = 2.
Constraints:
2 <= n <= 1001 <= edges.length <= n * (n - 1) / 2edges[i].length == 30 <= fromi < toi < n1 <= weighti, distanceThreshold <= 10^4- All pairs
(fromi, toi)are distinct.
Approaches
2 approaches with complexity analysis and trade-offs.
This approach tackles the problem by running a single-source shortest path (SSSP) algorithm from every city. Since all edge weights are positive, Dijkstra's algorithm is a perfect fit. By executing Dijkstra's n times, once for each city as the source, we can determine the shortest distance from every city to every other city. After obtaining these distances for a given source city, we count how many other cities are within the distanceThreshold and update our answer accordingly.
Algorithm
- Graph Representation: First, build an adjacency list to represent the graph. For each edge
[u, v, w], add(v, w)tou's list and(u, w)tov's list since the graph is bidirectional. - Iterate Through Cities: Loop through each city
ifrom0ton-1, treating each one as a potential starting node. - Run Dijkstra's Algorithm: For each city
i, run Dijkstra's algorithm to find the shortest path fromito all other cities. Use a priority queue to efficiently manage nodes to visit.- Initialize a
distarray with infinity for all nodes, anddist[i] = 0. - Push
{0, i}(distance, node) to the priority queue. - While the priority queue is not empty, extract the node
uwith the smallest distance and relax its edges, updating distances for its neighborsvif a shorter pathdist[u] + weight(u,v)is found.
- Initialize a
- Count Reachable Neighbors: After Dijkstra's completes for city
i, iterate through all citiesjfrom0ton-1. Count how many citiesj(wherej != i) havedist[j] <= distanceThreshold. - Find the Best City: Keep track of the city with the minimum number of reachable neighbors found so far. Let this be
min_countand the city beresult_city.- If the current city's neighbor count is less than or equal to
min_count, updatemin_countwith the new count andresult_citytoi. The<=condition ensures that in case of a tie, the city with the larger index is chosen (as we iterateifrom0ton-1).
- If the current city's neighbor count is less than or equal to
- Return Result: After checking all
ncities,result_citywill hold the answer.
Walkthrough
To implement this, we first construct an adjacency list representation of the graph from the input edges. Then, we loop through each city i from 0 to n-1. In each iteration, we use city i as the source and apply Dijkstra's algorithm. Dijkstra's uses a priority queue to always explore the node with the currently shortest known distance from the source, guaranteeing that we find the shortest paths in a greedy manner. Once the shortest distances from i to all other nodes are computed, we count how many of these distances are within the given distanceThreshold. We maintain a variable for the minimum count found so far and the corresponding city. If a city has a smaller count, or an equal count but a larger index, it becomes our new candidate for the answer. This process is repeated for all n cities to find the global best city.
import java.util.*; class Solution { public int findTheCity(int n, int[][] edges, int distanceThreshold) { List<List<int[]>> adj = new ArrayList<>(); for (int i = 0; i < n; i++) { adj.add(new ArrayList<>()); } for (int[] edge : edges) { adj.get(edge[0]).add(new int[]{edge[1], edge[2]}); adj.get(edge[1]).add(new int[]{edge[0], edge[2]}); } int minReachableCities = n; int resultCity = -1; for (int i = 0; i < n; i++) { int[] dist = dijkstra(n, adj, i); int reachableCount = 0; for (int j = 0; j < n; j++) { if (i != j && dist[j] <= distanceThreshold) { reachableCount++; } } if (reachableCount <= minReachableCities) { minReachableCities = reachableCount; resultCity = i; } } return resultCity; } private int[] dijkstra(int n, List<List<int[]>> adj, int startNode) { int[] dist = new int[n]; Arrays.fill(dist, Integer.MAX_VALUE); dist[startNode] = 0; // PriorityQueue stores {distance, node} PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[0])); pq.offer(new int[]{0, startNode}); while (!pq.isEmpty()) { int[] current = pq.poll(); int d = current[0]; int u = current[1]; if (d > dist[u]) { continue; } for (int[] neighbor : adj.get(u)) { int v = neighbor[0]; int weight = neighbor[1]; if (dist[u] != Integer.MAX_VALUE && dist[u] + weight < dist[v]) { dist[v] = dist[u] + weight; pq.offer(new int[]{dist[v], v}); } } } return dist; }}Complexity
Time
O(n * (E + n) log n). We run Dijkstra's algorithm `n` times. Each run of Dijkstra's with a binary heap has a complexity of `O((E+n) log n)`. For a dense graph, this approaches `O(n^3 log n)`.
Space
O(n + E), where `n` is the number of cities and `E` is the number of edges. This is for storing the adjacency list. In the worst case, `E` can be `O(n^2)`, making the space complexity `O(n^2)`.
Trade-offs
Pros
Conceptually straightforward, as it directly applies a standard SSSP algorithm.
Can be more efficient than Floyd-Warshall on very sparse graphs where
Eis much smaller thann^2.
Cons
For dense graphs, where the number of edges
Eis close ton^2, the time complexityO(n * E log n)becomesO(n^3 log n), which is less efficient than the Floyd-Warshall algorithm'sO(n^3).The implementation is slightly more complex than Floyd-Warshall, involving a priority queue and adjacency list setup for each of the
nruns.
The Floyd-Warshall algorithm is a classic dynamic programming approach for the all-pairs shortest path (APSP) problem. Given that we need to know the distances between all pairs of cities to solve this problem, Floyd-Warshall is a very natural and efficient choice, especially for the given constraints where n is up to 100. It calculates the shortest paths between all pairs of nodes in a single, unified process.
Algorithm
- Initialize Distance Matrix: Create an
n x nmatrixdistto store the shortest paths between all pairs of cities. Initializedist[i][i] = 0for alli, anddist[i][j] = infinityfor alli != j. - Populate Initial Distances: Iterate through the
edgesarray. For each edge[u, v, w], setdist[u][v] = wanddist[v][u] = w. - Apply Floyd-Warshall: Use three nested loops to find all-pairs shortest paths. The loops iterate through intermediate nodes
k, source nodesi, and destination nodesj.for k from 0 to n-1:for i from 0 to n-1:for j from 0 to n-1:dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
- Find the Result City: After the
distmatrix is computed, iterate through each cityifrom0ton-1.- For each
i, count the number of other citiesjwheredist[i][j] <= distanceThreshold. - Keep track of the city with the minimum count. If the current city's count is less than or equal to the minimum count found so far, update the result to the current city
i. This handles the tie-breaking rule.
- For each
- Return Result: The final city stored is the answer.
Walkthrough
This method begins by setting up an n x n distance matrix. Initially, the distance from a city to itself is 0, the distance between directly connected cities is their edge weight, and all other distances are infinite. The algorithm then systematically improves these path estimates. It iterates through every city k and considers it as a potential intermediate stop in the path from any city i to any city j. It updates the distance dist[i][j] if the path going through k (dist[i][k] + dist[k][j]) is shorter. After iterating through all possible intermediate cities k, the matrix contains the shortest path distances between every pair of cities. With this complete information, we can simply iterate through each city, count its neighbors within the distance threshold, and find the city that minimizes this count, respecting the tie-breaker rule.
import java.util.Arrays; class Solution { public int findTheCity(int n, int[][] edges, int distanceThreshold) { int[][] dist = new int[n][n]; // Use a large number for infinity, but not so large it overflows when added. int INF = 100000000; for (int i = 0; i < n; i++) { Arrays.fill(dist[i], INF); dist[i][i] = 0; } for (int[] edge : edges) { int u = edge[0]; int v = edge[1]; int w = edge[2]; dist[u][v] = w; dist[v][u] = w; } for (int k = 0; k < n; k++) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (dist[i][k] < INF && dist[k][j] < INF) { // Avoid overflow dist[i][j] = Math.min(dist[i][j], dist[i][k] + dist[k][j]); } } } } int minReachableCities = n; int resultCity = -1; for (int i = 0; i < n; i++) { int reachableCount = 0; for (int j = 0; j < n; j++) { if (i != j && dist[i][j] <= distanceThreshold) { reachableCount++; } } if (reachableCount <= minReachableCities) { minReachableCities = reachableCount; resultCity = i; } } return resultCity; }}Complexity
Time
O(n^3). The algorithm is dominated by the three nested loops, each running `n` times. The final step to find the result city takes `O(n^2)`, which is subsumed by `O(n^3)`.
Space
O(n^2), for storing the `n x n` distance matrix.
Trade-offs
Pros
Generally more efficient for this problem's constraints (
n <= 100) than running Dijkstra from each node, especially for dense graphs.The implementation is very concise and straightforward due to its systematic, triple-loop structure.
Its
O(n^3)performance is predictable and not dependent on the graph's structure (sparse vs. dense).
Cons
Can be slower than repeated Dijkstra's on very sparse graphs, although this is often not a significant factor for the given constraints.
Requires
O(n^2)space unconditionally, which might be high if memory is extremely constrained and the graph is sparse.
Solutions
Solution
class Solution {private int n;private int[][] g;private int[] dist;private boolean[] vis;private final int inf = 1 << 30;private int distanceThreshold;public int findTheCity(int n, int[][] edges, int distanceThreshold) { this.n = n; this.distanceThreshold = distanceThreshold; g = new int[n][n]; dist = new int[n]; vis = new boolean[n]; for (var e : g) { Arrays.fill(e, inf); } for (var e : edges) { int f = e[0], t = e[1], w = e[2]; g[f][t] = w; g[t][f] = w; } int ans = n, cnt = inf; for (int i = n - 1; i >= 0; --i) { int t = dijkstra(i); if (t < cnt) { cnt = t; ans = i; } } return ans; }private int dijkstra(int u) { Arrays.fill(dist, inf); Arrays.fill(vis, false); dist[u] = 0; for (int i = 0; i < n; ++i) { int k = -1; for (int j = 0; j < n; ++j) { if (!vis[j] && (k == -1 || dist[k] > dist[j])) { k = j; } } vis[k] = true; for (int j = 0; j < n; ++j) { dist[j] = Math.min(dist[j], dist[k] + g[k][j]); } } int cnt = 0; for (int d : dist) { if (d <= distanceThreshold) { ++cnt; } } return cnt; }}function findTheCity ( n , edges , distanceThreshold ) { const g = Array . from ({ length : n }, () => Array ( n ). fill ( Infinity )); const dist = Array ( n ). fill ( Infinity ); const vis = Array ( n ). fill ( false ); for ( const [ f , t , w ] of edges ) { g [ f ][ t ] = g [ t ][ f ] = w ; } const dijkstra = u => { dist . fill ( Infinity ); vis . fill ( false ); dist [ u ] = 0 ; for ( let i = 0 ; i < n ; ++ i ) { let k = - 1 ; for ( let j = 0 ; j < n ; ++ j ) { if ( ! vis [ j ] && ( k === - 1 || dist [ j ] < dist [ k ])) { k = j ; } } vis [ k ] = true ; for ( let j = 0 ; j < n ; ++ j ) { dist [ j ] = Math . min ( dist [ j ], dist [ k ] + g [ k ][ j ]); } } return dist . filter ( d => d <= distanceThreshold ). length ; }; let ans = n ; let cnt = Infinity ; for ( let i = n - 1 ; i >= 0 ; -- i ) { const t = dijkstra ( i ); if ( t < cnt ) { cnt = t ; ans = i ; } } return ans ; }class Solution {public: int findTheCity(int n, vector<vector<int>> &edges, int distanceThreshold) { int g[n][n]; int dist[n]; bool vis[n]; memset(g, 0x3f, sizeof(g)); for (auto &e : edges) { int f = e[0], t = e[1], w = e[2]; g[f][t] = g[t][f] = w; } auto dijkstra = [&](int u) { memset(dist, 0x3f, sizeof(dist)); memset(vis, 0, sizeof(vis)); dist[u] = 0; for (int i = 0; i < n; ++i) { int k = -1; for (int j = 0; j < n; ++j) { if (!vis[j] && (k == -1 || dist[j] < dist[k])) { k = j; } } vis[k] = true; for (int j = 0; j < n; ++j) { dist[j] = min(dist[j], dist[k] + g[k][j]); } } return count_if(dist, dist + n, [&](int d) { return d <= distanceThreshold; }); }; int ans = n, cnt = n + 1; for (int i = n - 1; ~i; --i) { int t = dijkstra(i); if (t < cnt) { cnt = t; ans = i; } } return ans; }};class Solution: # dist[j] = min(dist[j], dist[k] + g[k][j]) if dist [ k ] + g [ k ][ j ] < dist [ j ]: dist [ j ] = dist [ k ] + g [ k ][ j ] return sum ( d <= distanceThreshold for d in dist ) g = [[ inf ] * n for _ in range ( n )] for f , t , w in edges : g [ f ][ t ] = g [ t ][ f ] = w ans , cnt = n , inf for i in range ( n - 1 , - 1 , - 1 ): if ( t : = dijkstra ( i )) < cnt : cnt , ans = t , i return ans def findTheCity(self, n: int, edges: List[List[int]], distanceThreshold: int) -> int: def dijkstra(u: int) -> int: dist = [inf] * n dist[u] = 0 vis = [False] * n for _ in range(n): k = - 1 for j in range(n): if not vis[j] and (k == - 1 or dist[k] > dist[j]): k = j vis[k] = True for j in range(n):Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.