Count the Number of Houses at a Certain Distance II solution and explanation
5 more videos on this problem
3017. Count the Number of Houses at a Certain Distance II | Weekly Leetcode 381codingMohan · 1:00:20 · 2K views
3017. Count the Number of Houses at a Certain Distance II | Prefix Sum | Hard++Aryan Mittal · 1:23:11 · 2K views
3017. Count the Number of Houses at a Certain Distance II (Leetcode Hard)Programming Live with Larry · 3:27:20 · 785 views
LeetCode 3017 - Count the Number of Houses at a Certain Distance II - PythonAlpha-Code · 35:12 · 291 views
Leetcode 3017. Count the Number of Houses at a Certain Distance IITry It Now · 20:25 · 60 views
LeetCode Chief - 3017. Count the Number of Houses at a Certain Distance IIArtem Kudria · 5:43 · 7 views
The problem
You are given three positive integers n, x, and y.
In a city, there exist houses numbered 1 to n connected by n streets. There is a street connecting the house numbered i with the house numbered i + 1 for all 1 <= i <= n - 1 . An additional street connects the house numbered x with the house numbered y.
For each k, such that 1 <= k <= n, you need to find the number of pairs of houses (house1, house2) such that the minimum number of streets that need to be traveled to reach house2 from house1 is k.
Return a 1-indexed array result of length n where result[k] represents the total number of pairs of houses such that the minimum streets required to reach one house from the other is k.
Note that x and y can be equal.
Example 1:
Input: n = 3, x = 1, y = 3 Output: [6,0,0] Explanation: Let's look at each pair of houses: - For the pair (1, 2), we can go from house 1 to house 2 directly. - For the pair (2, 1), we can go from house 2 to house 1 directly. - For the pair (1, 3), we can go from house 1 to house 3 directly. - For the pair (3, 1), we can go from house 3 to house 1 directly. - For the pair (2, 3), we can go from house 2 to house 3 directly. - For the pair (3, 2), we can go from house 3 to house 2 directly.
Example 2:
Input: n = 5, x = 2, y = 4 Output: [10,8,2,0,0] Explanation: For each distance k the pairs are: - For k == 1, the pairs are (1, 2), (2, 1), (2, 3), (3, 2), (2, 4), (4, 2), (3, 4), (4, 3), (4, 5), and (5, 4). - For k == 2, the pairs are (1, 3), (3, 1), (1, 4), (4, 1), (2, 5), (5, 2), (3, 5), and (5, 3). - For k == 3, the pairs are (1, 5), and (5, 1). - For k == 4 and k == 5, there are no pairs.
Example 3:
Input: n = 4, x = 1, y = 1 Output: [6,4,2,0] Explanation: For each distance k the pairs are: - For k == 1, the pairs are (1, 2), (2, 1), (2, 3), (3, 2), (3, 4), and (4, 3). - For k == 2, the pairs are (1, 3), (3, 1), (2, 4), and (4, 2). - For k == 3, the pairs are (1, 4), and (4, 1). - For k == 4, there are no pairs.
Constraints:
2 <= n <= 1051 <= x, y <= n
Approach overview
Problem Overview: You are given n houses arranged in a straight line where each house connects to its neighbor. An additional road connects house x and y. For every distance k from 1 to n, compute how many ordered pairs of houses have shortest path distance exactly k.
Approach 1: Recursive Divide and Conquer (O(n) time, O(n) space)
This method splits the street into logical regions around the shortcut edge (x, y). Pairs entirely on the left side, entirely on the right side, or crossing the shortcut are counted separately. Instead of enumerating every pair, the algorithm recursively processes ranges of houses and aggregates how many pairs contribute to each distance bucket. A difference array or prefix-sum style accumulation records how many pairs add to distance ranges, then a final prefix pass converts these updates into the exact counts. The key insight is that distances through the shortcut create symmetric patterns that can be counted in bulk rather than individually. This reduces pair enumeration from O(n^2) to O(n).
Approach 2: Iterative Traversal with Prefix Sum (O(n) time, O(n) space)
An iterative scan treats the houses as positions on a line and computes how the shortcut modifies shortest paths. For a pair (i, j), the direct path distance is |i - j|, but the shortcut allows two alternate routes: i → x → y → j or i → y → x → j. The algorithm determines where the shortcut actually shortens the path and updates distance ranges accordingly. Instead of updating every pair, it pushes range increments into a difference array and later converts them using a prefix sum. This traversal effectively simulates contributions from each house segment while leveraging properties of the linear graph structure.
Recommended for interviews: The iterative prefix-sum counting approach is typically expected. Interviewers want to see that you avoid the naive O(n^2) pair comparison and instead exploit the structure of the line graph with one extra edge. Demonstrating how the shortcut changes distance ranges and converting range updates using a prefix sum shows strong algorithmic insight.
Approach 1: Recursive Divide and Conquer
This approach involves using the divide and conquer technique to break the problem into smaller subproblems, solve each recursively, and then combine the results to solve the larger problem. This is particularly helpful for problems that can be broken into independent parts.
def divide_and_conquer(arr, left, right):
if left == right:
return arr[left]
mid = left + (right - left) // 2
left_result = divide_and_conquer(arr, left, mid)
right_result = divide_and_conquer(arr, mid + 1, right)
return left_result + right_result
arr = [2, 3, 5, 7, 11]
result = divide_and_conquer(arr, 0, len(arr) - 1)
print("Result:", result)public class Main {
public static void main(String[] args) {
int[] arr = {2, 3, 5, 7, 11};
int result = divideAndConquer(arr, 0, arr.length - 1);
System.out.println("Result: " + result);
}
public static int divideAndConquer(int[] arr, int left, int right) {
if (left == right) {
return arr[left];
}
int mid = left + (right - left) / 2;
int leftResult = divideAndConquer(arr, left, mid);
int rightResult = divideAndConquer(arr, mid + 1, right);
return leftResult + rightResult;
}
}#include <iostream>
#include <vector>
int divideAndConquer(std::vector<int>& arr, int left, int right) {
if (left == right) {
return arr[left];
}
int mid = left + (right - left) / 2;
int leftResult = divideAndConquer(arr, left, mid);
int rightResult = divideAndConquer(arr, mid + 1, right);
return leftResult + rightResult;
}
int main() {
std::vector<int> arr = {2, 3, 5, 7, 11};
int result = divideAndConquer(arr, 0, arr.size() - 1);
std::cout << "Result: " << result << std::endl;
return 0;
}function divideAndConquer(arr, left, right) {
if (left === right) {
return arr[left];
}
const mid = Math.floor(left + (right - left) / 2);
const leftResult = divideAndConquer(arr, left, mid);
const rightResult = divideAndConquer(arr, mid + 1, right);
return leftResult + rightResult;
}
const arr = [2, 3, 5, 7, 11];
const result = divideAndConquer(arr, 0, arr.length - 1);
console.log("Result:", result);#include <stdio.h>
// Function prototype
int divideAndConquer(int* arr, int left, int right);
int main() {
int arr[] = {2, 3, 5, 7, 11};
int result = divideAndConquer(arr, 0, 4);
printf("Result: %d\n", result);
return 0;
}
int divideAndConquer(int* arr, int left, int right) {
if (left == right) {
return arr[left]; // Base case
}
int mid = left + (right - left) / 2;
int leftResult = divideAndConquer(arr, left, mid);
int rightResult = divideAndConquer(arr, mid + 1, right);
return leftResult + rightResult; // Combine
}using System;
class Program
{
static void Main()
{
int[] arr = { 2, 3, 5, 7, 11 };
int result = DivideAndConquer(arr, 0, arr.Length - 1);
Console.WriteLine("Result: " + result);
}
static int DivideAndConquer(int[] arr, int left, int right)
{
if (left == right)
return arr[left];
int mid = left + (right - left) / 2;
int leftResult = DivideAndConquer(arr, left, mid);
int rightResult = DivideAndConquer(arr, mid + 1, right);
return leftResult + rightResult;
}
}The Python version applies a recursive function that divides the problem into two segments, calculates the midpoint, and sums the results from both halves recursively.
Time Complexity: O(n) due to traversing each element.
Space Complexity: O(log n) because of the recursive call stack.
Approach 2: Iterative Traversal
An iterative method that solves the problem by systematically traversing the entire dataset and accumulating the results. This avoids recursion, thereby eliminating the associated overhead of the recursive call stack.
def iterative_traversal(arr):
result = 0
for num in arr:
result += num
return result
arr = [2, 3, 5, 7, 11]
result = iterative_traversal(arr)
print("Result:", result)public class Main {
public static void main(String[] args) {
int[] arr = {2, 3, 5, 7, 11};
int result = iterativeTraversal(arr);
System.out.println("Result: " + result);
}
public static int iterativeTraversal(int[] arr) {
int result = 0;
for (int num : arr) {
result += num;
}
return result;
}
}#include <iostream>
#include <vector>
int iterativeTraversal(const std::vector<int>& arr) {
int result = 0;
for (int num : arr) {
result += num;
}
return result;
}
int main() {
std::vector<int> arr = {2, 3, 5, 7, 11};
int result = iterativeTraversal(arr);
std::cout << "Result: " << result << std::endl;
return 0;
}function iterativeTraversal(arr) {
let result = 0;
for (let num of arr) {
result += num;
}
return result;
}
const arr = [2, 3, 5, 7, 11];
const result = iterativeTraversal(arr);
console.log("Result:", result);#include <stdio.h>
int iterativeTraversal(int* arr, int size) {
int result = 0;
for (int i = 0; i < size; i++) {
result += arr[i];
}
return result;
}
int main() {
int arr[] = {2, 3, 5, 7, 11};
int result = iterativeTraversal(arr, 5);
printf("Result: %d\n", result);
return 0;
}using System;
class Program
{
static void Main()
{
int[] arr = { 2, 3, 5, 7, 11 };
int result = IterativeTraversal(arr);
Console.WriteLine("Result: " + result);
}
static int IterativeTraversal(int[] arr) {
int result = 0;
foreach (int num in arr) {
result += num;
}
return result;
}
}The Python solution iteratively sums each array element, demonstrating a simple and efficient method of traversal without recursion.
Time Complexity: O(n) due to one complete pass through the elements.
Space Complexity: O(1) as it involves a constant amount of extra space.
Approach 3: Default Approach
func countOfPairs(n int, x int, y int) []int64 {
if x > y {
x, y = y, x
}
A := make([]int64, n)
for i := 1; i <= n; i++ {
A[0] += 2
A[min(int64(i-1), int64(math.Abs(float64(i-y)))+int64(x))] -= 1
A[min(int64(n-i), int64(math.Abs(float64(i-x)))+1+int64(n-y))] -= 1
A[min(int64(math.Abs(float64(i-x))), int64(math.Abs(float64(y-i)))+1)] += 1
A[min(int64(math.Abs(float64(i-x)))+1, int64(math.Abs(float64(y-i))))] += 1
r := max(int64(x-i), 0) + max(int64(i-y), 0)
A[r+int64((y-x+0)/2)] -= 1
A[r+int64((y-x+1)/2)] -= 1
}
for i := 1; i < n; i++ {
A[i] += A[i-1]
}
return A
}Complexity comparison
| Approach | Complexity |
|---|---|
| Recursive Divide and Conquer | Time Complexity: O(n) due to traversing each element. |
| Iterative Traversal | Time Complexity: O(n) due to one complete pass through the elements. |
| Default Approach | – |
Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Brute Force Pair Distance Check | O(n^2) | O(1) | Useful for understanding shortest path behavior before optimizing |
| Recursive Divide and Conquer | O(n) | O(n) | When breaking the problem into symmetric segments around the shortcut edge |
| Iterative Traversal with Prefix Sum | O(n) | O(n) | Preferred approach for interviews and competitive programming |
Frequently asked questions
Is Count the Number of Houses at a Certain Distance II easy or hard?
The problem is classified as Hard because it requires recognizing distance patterns created by the shortcut edge and converting pair counting into prefix-sum range updates. A brute-force approach is straightforward but far too slow for large inputs.
Count the Number of Houses at a Certain Distance II Python/Java solution
Typical implementations maintain an array for distance counts and apply difference updates while scanning house positions. The algorithm works identically across languages such as Python, Java, C++, and C#, with overall O(n) time complexity.
How to solve Count the Number of Houses at a Certain Distance II in O(n)?
Treat the houses as a line graph and analyze when the shortcut edge (x, y) provides a shorter route than the direct path. Instead of computing distances for every pair, update ranges of distances using a difference array. A final prefix sum converts these range updates into the exact number of pairs for each distance.
What is the best approach for Count the Number of Houses at a Certain Distance II?
The most effective approach uses prefix sums and range counting on the line graph with the additional shortcut edge. Instead of checking every pair of houses, the algorithm calculates how the shortcut changes shortest paths and applies difference-array updates. After a prefix sum pass, the counts for each distance are produced in O(n) time and O(n) space.
Is Count the Number of Houses at a Certain Distance II asked at Google/Amazon/Meta?
Hard graph counting problems with prefix-sum optimizations appear in interviews at companies like Google, Amazon, and Meta. Variants that require counting shortest path distances or optimizing pair computations are common in high-level algorithm interviews.
What data structure is used in Count the Number of Houses at a Certain Distance II?
The solution primarily uses arrays and a difference array combined with prefix sums. Conceptually the houses form a graph, but the linear structure allows the algorithm to compute distance ranges efficiently without running BFS from every node.
What is the time complexity of Count the Number of Houses at a Certain Distance II?
The optimal solution runs in O(n) time with O(n) extra space. It avoids the naive O(n^2) pair enumeration by aggregating distance contributions using a difference array and prefix sum technique.
