475. Heaters
Problem Description
You need to warm all houses using heaters with a fixed radius. Each heater can warm any house that falls within its warming radius on both sides.
You're given two arrays:
houses: positions of houses on a horizontal lineheaters: positions of heaters on a horizontal line
Your task is to find the minimum radius that all heaters must have to ensure every house is covered by at least one heater. All heaters will use the same radius value.
A house at position x is warmed by a heater at position y with radius r if the distance between them is at most r, meaning |x - y| <= r.
For example:
- If a heater is at position 5 with radius 2, it can warm houses at positions 3, 4, 5, 6, and 7
- If houses are at
[1, 2, 3]and heaters are at[2], a radius of 1 would warm all houses since the heater at position 2 can reach houses at positions 1, 2, and 3
The solution uses binary search on the radius value combined with a greedy checking mechanism. After sorting both arrays, it searches for the smallest radius between 0 and 10^9. For each candidate radius mid, it checks if all houses can be covered by using a two-pointer technique: advancing through houses and heaters to verify if each house falls within the range [heater_position - radius, heater_position + radius] of some heater.
Intuition
The key insight is recognizing this as an optimization problem where we need to find the minimum value (radius) that satisfies a condition (all houses are covered). This pattern naturally suggests binary search on the answer.
Why binary search works here? Consider that if a radius r can warm all houses, then any radius larger than r will also work. Conversely, if radius r cannot warm all houses, then any smaller radius will also fail. This creates a monotonic property: there exists a threshold radius where all values below it fail and all values at or above it succeed.
The challenge then becomes: given a specific radius, how do we efficiently check if all houses can be warmed? After sorting both arrays, we can use a greedy two-pointer approach. We process houses from left to right and for each house, we find if it can be covered by the current heater. If a house is too far to the left of the current heater (outside its range), we know this radius is insufficient. If a house is too far to the right, we move to the next heater and try again.
The sorting is crucial because it allows us to process houses and heaters in order, ensuring we don't miss any coverage gaps. Once sorted, we can confidently say that if we can't cover a house with the current or any subsequent heater, then the radius is too small.
The range for binary search [0, 10^9] is chosen to cover all possible distances since house and heater positions are typically bounded by this range in the problem constraints. We keep narrowing down this range until we find the exact minimum radius needed.
Solution Implementation
1class Solution:
2 def findRadius(self, houses: List[int], heaters: List[int]) -> int:
3 houses.sort()
4 heaters.sort()
5
6 def feasible(radius):
7 house_idx = 0
8 heater_idx = 0
9
10 while house_idx < len(houses):
11 if heater_idx >= len(heaters):
12 return False
13
14 min_coverage = heaters[heater_idx] - radius
15 max_coverage = heaters[heater_idx] + radius
16
17 if houses[house_idx] < min_coverage:
18 return False
19 if houses[house_idx] > max_coverage:
20 heater_idx += 1
21 else:
22 house_idx += 1
23
24 return True
25
26 left, right = 0, int(1e9)
27 first_true_index = -1
28
29 while left <= right:
30 mid = (left + right) // 2
31 if feasible(mid):
32 first_true_index = mid
33 right = mid - 1
34 else:
35 left = mid + 1
36
37 return first_true_index
381class Solution {
2 public int findRadius(int[] houses, int[] heaters) {
3 Arrays.sort(houses);
4 Arrays.sort(heaters);
5
6 int left = 0, right = 1000000000;
7 int firstTrueIndex = -1;
8
9 while (left <= right) {
10 int mid = left + (right - left) / 2;
11 if (feasible(houses, heaters, mid)) {
12 firstTrueIndex = mid;
13 right = mid - 1;
14 } else {
15 left = mid + 1;
16 }
17 }
18
19 return firstTrueIndex;
20 }
21
22 private boolean feasible(int[] houses, int[] heaters, int radius) {
23 int houseIdx = 0;
24 int heaterIdx = 0;
25
26 while (houseIdx < houses.length) {
27 if (heaterIdx >= heaters.length) {
28 return false;
29 }
30
31 int minCoverage = heaters[heaterIdx] - radius;
32 int maxCoverage = heaters[heaterIdx] + radius;
33
34 if (houses[houseIdx] < minCoverage) {
35 return false;
36 }
37 if (houses[houseIdx] > maxCoverage) {
38 heaterIdx++;
39 } else {
40 houseIdx++;
41 }
42 }
43
44 return true;
45 }
46}
471class Solution {
2public:
3 int findRadius(vector<int>& houses, vector<int>& heaters) {
4 sort(houses.begin(), houses.end());
5 sort(heaters.begin(), heaters.end());
6
7 auto feasible = [&](int radius) {
8 int houseIdx = 0;
9 int heaterIdx = 0;
10
11 while (houseIdx < (int)houses.size()) {
12 if (heaterIdx >= (int)heaters.size()) {
13 return false;
14 }
15
16 int minCoverage = heaters[heaterIdx] - radius;
17 int maxCoverage = heaters[heaterIdx] + radius;
18
19 if (houses[houseIdx] < minCoverage) {
20 return false;
21 }
22 if (houses[houseIdx] > maxCoverage) {
23 heaterIdx++;
24 } else {
25 houseIdx++;
26 }
27 }
28
29 return true;
30 };
31
32 int left = 0, right = 1000000000;
33 int firstTrueIndex = -1;
34
35 while (left <= right) {
36 int mid = left + (right - left) / 2;
37 if (feasible(mid)) {
38 firstTrueIndex = mid;
39 right = mid - 1;
40 } else {
41 left = mid + 1;
42 }
43 }
44
45 return firstTrueIndex;
46 }
47};
481function findRadius(houses: number[], heaters: number[]): number {
2 houses.sort((a, b) => a - b);
3 heaters.sort((a, b) => a - b);
4
5 const feasible = (radius: number): boolean => {
6 let houseIdx = 0;
7 let heaterIdx = 0;
8
9 while (houseIdx < houses.length) {
10 if (heaterIdx >= heaters.length) {
11 return false;
12 }
13
14 const minCoverage = heaters[heaterIdx] - radius;
15 const maxCoverage = heaters[heaterIdx] + radius;
16
17 if (houses[houseIdx] < minCoverage) {
18 return false;
19 }
20 if (houses[houseIdx] > maxCoverage) {
21 heaterIdx++;
22 } else {
23 houseIdx++;
24 }
25 }
26
27 return true;
28 };
29
30 let left = 0;
31 let right = 1000000000;
32 let firstTrueIndex = -1;
33
34 while (left <= right) {
35 const mid = Math.floor((left + right) / 2);
36 if (feasible(mid)) {
37 firstTrueIndex = mid;
38 right = mid - 1;
39 } else {
40 left = mid + 1;
41 }
42 }
43
44 return firstTrueIndex;
45}
46Solution Approach
The solution uses binary search on the answer space combined with a greedy validation function.
Step 1: Sorting Both arrays are sorted to enable efficient checking using a two-pointer technique.
Step 2: Binary Search Setup
left = 0(minimum possible radius)right = 10^9(maximum possible radius)first_true_index = -1(tracks the answer)
Step 3: Feasible Function
The feasible(radius) function determines if all houses can be covered with the given radius. This creates a boolean pattern:
radius: 0 1 2 3 4 5 ... feasible: false false false false false true ...
The checking logic uses two pointers:
- For each heater, its coverage range is
[heater - radius, heater + radius] - If a house is left of all heater ranges, the radius is too small
- If a house is beyond current heater's range, try the next heater
Step 4: Binary Search Template
left, right = 0, int(1e9)
first_true_index = -1
while left <= right:
mid = (left + right) // 2
if feasible(mid):
first_true_index = mid
right = mid - 1 # Try smaller radius
else:
left = mid + 1 # Need larger radius
return first_true_index
Time Complexity: O((m + n) log(m + n) + (m + n) log(10^9)) where m is houses, n is heaters.
Space Complexity: O(1) excluding sorting space.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through with houses = [1, 5, 15] and heaters = [6, 10].
Step 1: Sort both arrays
- Houses:
[1, 5, 15](already sorted) - Heaters:
[6, 10](already sorted)
Step 2: Binary search with template
left = 0,right = 10^9,first_true_index = -1
Key iterations (skipping large radius checks):
When mid = 5:
- Check
feasible(5):- Heater 6 covers range
[1, 11] - House 1:
1 ≥ 1and1 ≤ 11→ covered ✓ - House 5:
5 ≥ 1and5 ≤ 11→ covered ✓ - House 15:
15 > 11→ try next heater - Heater 10 covers range
[5, 15] - House 15:
15 ≥ 5and15 ≤ 15→ covered ✓ - Result:
True
- Heater 6 covers range
first_true_index = 5,right = 4
When mid = 2 (in range [0, 4]):
- Check
feasible(2):- Heater 6 covers range
[4, 8] - House 1:
1 < 4→ not covered! - Result:
False
- Heater 6 covers range
left = 3
When mid = 4 (in range [3, 4]):
- Check
feasible(4):- Heater 6 covers range
[2, 10] - House 1:
1 < 2→ not covered! - Result:
False
- Heater 6 covers range
left = 5
Loop ends: left = 5 > right = 4
Answer: first_true_index = 5
Verification:
- Heater 6 with radius 5: covers
[1, 11]→ houses 1 and 5 - Heater 10 with radius 5: covers
[5, 15]→ house 15 - All houses covered with minimum radius 5.
Time and Space Complexity
Time Complexity: O((m + n) * log(m + n) + (m + n) * log(max_distance))
- Sorting houses takes
O(m * log(m))wheremis the number of houses - Sorting heaters takes
O(n * log(n))wherenis the number of heaters - Binary search runs for
O(log(max_distance))iterations, wheremax_distanceis the search space from 0 to10^9 - Each binary search iteration calls the
check()function, which takesO(m + n)time in the worst case as it iterates through all houses and potentially all heaters - Overall:
O(m * log(m) + n * log(n) + (m + n) * log(10^9)) - Since
log(10^9) ≈ 30is a constant, and typicallym + ndominates the sorting complexity, this simplifies toO((m + n) * log(m + n) + (m + n) * log(max_distance))
Space Complexity: O(1)
- The sorting operations are done in-place (Python's sort uses Timsort which requires
O(min(m, n))auxiliary space in worst case, but typicallyO(1)for already sorted or small arrays) - The algorithm only uses a constant amount of extra variables (
i,j,left,right,mid,mi,mx,r) - No additional data structures are created
- Therefore, the space complexity is
O(1)excluding the space used by sorting
Common Pitfalls
1. Using Wrong Binary Search Template Variant
A common mistake is using while left < right with right = mid instead of the standard template.
Incorrect:
while left < right: mid = (left + right) // 2 if feasible(mid): right = mid else: left = mid + 1 return left
Correct (template-compliant):
first_true_index = -1 while left <= right: mid = (left + right) // 2 if feasible(mid): first_true_index = mid right = mid - 1 else: left = mid + 1 return first_true_index
The template approach explicitly tracks the answer and handles edge cases consistently.
2. Incorrect Coverage Check Logic
Not checking both boundaries of the heater's coverage range.
Incorrect:
def feasible(radius):
for heater in heaters:
while house_idx < len(houses) and houses[house_idx] <= heater + radius:
house_idx += 1
return house_idx == len(houses) # Missing left boundary check!
Correct:
if houses[house_idx] < min_coverage: return False # House is too far left of all heaters
3. Forgetting to Sort Arrays
The two-pointer feasibility check requires sorted arrays.
# Always sort both arrays first houses.sort() heaters.sort()
4. Not Handling Edge Cases
When all houses are covered by the first heater, or when arrays have different sizes.
The feasible function handles these automatically with proper two-pointer logic.
Which type of traversal does breadth first search do?
Recommended Readings
Tech Interview Pattern Two Pointers Introduction If you prefer videos here's a super quick introduction to Two Pointers div class responsive iframe iframe src https www youtube com embed xZ4AfXHQ1VQ title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture allowfullscreen iframe div Two pointers is a common interview
https assets algo monster cover_photos Binary_Search svg Binary Search Intuition Binary search is an efficient array search algorithm It works by narrowing down the search range by half each time If you have looked up a word in a physical dictionary you've already used binary search in real life Let's
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
Want a Structured Path to Master System Design Too? Don’t Miss This!