LeetCode 3809 - Best Reachable Tower
This problem asks us to identify the "best reachable tower" from a given center location within a specified Manhattan distance radius. Each tower has a coordinate (xi, yi) and a quality factor qi.
Difficulty: 🟡 Medium
Topics: Array
Solution
Problem Understanding
This problem asks us to identify the "best reachable tower" from a given center location within a specified Manhattan distance radius. Each tower has a coordinate (xi, yi) and a quality factor qi. A tower is considered reachable if its Manhattan distance from the center (cx, cy) is less than or equal to the given radius. Among all reachable towers, we are asked to select the one with the maximum quality factor. If multiple towers share the maximum quality, the tie is broken by selecting the lexicographically smallest coordinate. If no tower is reachable, we return [-1, -1].
The inputs consist of a list of towers, each represented as [xi, yi, qi], a center [cx, cy], and an integer radius. The constraints indicate that the number of towers can be large (up to 100,000), and the coordinates and quality factors can also be as large as 100,000. This tells us that our solution must be linear or nearly linear, and we should avoid nested loops over all possible positions.
Important edge cases include when no towers are reachable, when multiple towers have the same maximum quality factor, and when towers are located exactly at the Manhattan distance boundary. The problem guarantees valid input ranges, so negative coordinates are not a concern.
Approaches
A brute-force approach would iterate through every tower, compute its Manhattan distance from the center, and check whether it is within the radius. For reachable towers, we would track the maximum quality factor and, in the case of ties, compare coordinates lexicographically. This approach is simple and correct because it examines all towers, but it is already optimal in time complexity for this problem since we must inspect each tower at least once. There is no faster method because the data is unsorted, and any solution must evaluate the distance and quality of every tower.
The key observation is that the problem reduces to a single pass through the array: for each tower, compute its Manhattan distance, check if it is reachable, and update a running best tower based on quality and lexicographic ordering. No additional data structures are required, so space complexity is constant.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n) | O(1) | Single pass checking reachability and maintaining maximum |
| Optimal | O(n) | O(1) | Same as brute force; no sorting or extra structures needed |
Algorithm Walkthrough
- Initialize a variable
best_toweras[-1, -1]to store the current best tower coordinates, andmax_qualityas-1to track the highest quality seen among reachable towers. - Iterate over each tower
[xi, yi, qi]in thetowersarray. - Compute the Manhattan distance from the center as
abs(xi - cx) + abs(yi - cy). This tells us if the tower is reachable. - If the distance is less than or equal to the radius, the tower is reachable. Compare its quality
qiwithmax_quality. - If
qiis greater thanmax_quality, updatemax_qualitytoqiandbest_towerto[xi, yi]. - If
qiequalsmax_quality, check if[xi, yi]is lexicographically smaller thanbest_tower. If it is, updatebest_towerto[xi, yi]. - After processing all towers, return
best_tower.
Why it works: The algorithm maintains the invariant that best_tower always contains the coordinates of the highest-quality reachable tower encountered so far, with lexicographic tie-breaking. Since every tower is examined exactly once, we are guaranteed to find the correct answer.
Python Solution
from typing import List
class Solution:
def bestTower(self, towers: List[List[int]], center: List[int], radius: int) -> List[int]:
cx, cy = center
best_tower = [-1, -1]
max_quality = -1
for x, y, q in towers:
manhattan_distance = abs(x - cx) + abs(y - cy)
if manhattan_distance <= radius:
if q > max_quality or (q == max_quality and [x, y] < best_tower):
max_quality = q
best_tower = [x, y]
return best_tower
In the implementation, we unpack the center coordinates into cx and cy. For each tower, we compute the Manhattan distance and check if it is reachable. If it is, we use a combined condition to decide whether to update best_tower: either the tower has a higher quality or ties in quality but is lexicographically smaller. Finally, we return the result.
Go Solution
func bestTower(towers [][]int, center []int, radius int) []int {
cx, cy := center[0], center[1]
bestTower := []int{-1, -1}
maxQuality := -1
for _, tower := range towers {
x, y, q := tower[0], tower[1], tower[2]
manhattan := abs(x-cx) + abs(y-cy)
if manhattan <= radius {
if q > maxQuality || (q == maxQuality && (x < bestTower[0] || (x == bestTower[0] && y < bestTower[1]))) {
maxQuality = q
bestTower[0] = x
bestTower[1] = y
}
}
}
return bestTower
}
func abs(a int) int {
if a < 0 {
return -a
}
return a
}
In Go, we manually define an abs function for integer absolute value. Lexicographic comparison is done with explicit checks on x and y because Go slices do not support direct comparison. Otherwise, the logic mirrors the Python implementation.
Worked Examples
Example 1
Input: towers = [[1,2,5], [2,1,7], [3,1,9]], center = [1,1], radius = 2
| Tower | Manhattan Distance | Reachable? | max_quality | best_tower |
|---|---|---|---|---|
| [1,2,5] | 1 | Yes | 5 | [1,2] |
| [2,1,7] | 1 | Yes | 7 | [2,1] |
| [3,1,9] | 2 | Yes | 9 | [3,1] |
Output: [3,1]
Example 2
Input: towers = [[1,3,4], [2,2,4], [4,4,7]], center = [0,0], radius = 5
| Tower | Manhattan Distance | Reachable? | max_quality | best_tower |
|---|---|---|---|---|
| [1,3,4] | 4 | Yes | 4 | [1,3] |
| [2,2,4] | 4 | Yes | 4 | [1,3] (lex smaller) |
| [4,4,7] | 8 | No | 4 | [1,3] |
Output: [1,3]
Example 3
Input: towers = [[5,6,8], [0,3,5]], center = [1,2], radius = 1
All towers are out of reach. Output: [-1,-1]
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | Each tower is visited exactly once and distance calculation is O(1) |
| Space | O(1) | Only a few variables are used to track best tower and maximum quality |
The solution is linear in the number of towers, which is optimal since we must inspect each tower at least once.
Test Cases
sol = Solution()
# Provided examples
assert sol.bestTower([[1,2,5], [2,1,7], [3,1,9]], [1,1], 2) == [3,1] # maximum quality tower
assert sol.bestTower([[1,3,4], [2,2,4], [4,4,7]], [0,0], 5) == [1,3] # tie-breaking lexicographically
assert sol.bestTower([[5,6,8], [0,3,5]], [1,2], 1) == [-1,-1] # no reachable towers
# Edge case: only one tower reachable
assert sol.bestTower([[0,0,1]], [0,0], 0) == [0,0]
# Edge case: multiple towers same quality at same distance
assert sol.bestTower([[1,1,5], [1,2,5], [2,1,5]], [0,0], 3) == [1,1]
# Edge case: large radius includes all
assert sol.bestTower([[100000,100000,1]], [0,0], 200000) == [100000,100000]
# Edge case: zero radius, only exact center reachable
assert sol.bestTower([[1,1,10], [0,0,5]], [0,0], 0) == [0,0