1385. Find the Distance Value Between Two Arrays
Problem Description
You are given two integer arrays arr1
and arr2
, and an integer d
. Your task is to find the distance value between these two arrays.
The distance value is defined as the count of elements from arr1
that satisfy a specific condition. For an element arr1[i]
to be counted, there should not be any element arr2[j]
where the absolute difference between them is less than or equal to d
.
In mathematical terms, an element arr1[i]
contributes to the distance value if for all elements in arr2[j]
, the condition |arr1[i] - arr2[j]| > d
holds true.
For example:
- If
arr1 = [4, 5, 8]
,arr2 = [10, 9, 1, 8]
, andd = 2
- For
arr1[0] = 4
: Check against all elements inarr2
|4 - 10| = 6 > 2
✓|4 - 9| = 5 > 2
✓|4 - 1| = 3 > 2
✓|4 - 8| = 4 > 2
✓- Since all differences are greater than
d
, this element counts.
- Similarly check for other elements in
arr1
- Count all elements from
arr1
that satisfy the condition
The solution uses sorting and binary search optimization. After sorting arr2
, for each element x
in arr1
, it uses binary search to find if there's any element in the sorted arr2
within the range [x - d, x + d]
. If no such element exists in this range, then x
contributes to the distance value.
Intuition
The brute force approach would be to check every element in arr1
against every element in arr2
, which would take O(n * m)
time. However, we can optimize this by recognizing a key insight: for each element x
in arr1
, we need to check if there's any element in arr2
within the range [x - d, x + d]
.
This "range checking" problem naturally leads us to think about sorting and binary search. If we sort arr2
, the elements that could potentially violate our distance requirement (those within distance d
from x
) would form a contiguous segment in the sorted array.
For any element x
from arr1
, the elements in arr2
that would make it invalid are those where |x - arr2[j]| <= d
, which can be rewritten as x - d <= arr2[j] <= x + d
. In a sorted arr2
, all such elements would be consecutive.
Using binary search, we can quickly find the leftmost position where an element could be >= x - d
. If this position doesn't exist (we've gone past the array), or if the element at this position is > x + d
, then no element in arr2
is within distance d
from x
, meaning x
contributes to our answer.
This approach reduces our time complexity from O(n * m)
to O(m log m + n log m)
, where the first term is for sorting arr2
and the second term is for performing binary search for each element in arr1
.
The beauty of this solution lies in transforming a "check all pairs" problem into a "find if any element exists in a range" problem, which can be efficiently solved with sorting and binary search.
Learn more about Two Pointers, Binary Search and Sorting patterns.
Solution Approach
The solution implements the sorting and binary search strategy to efficiently find the distance value between two arrays.
Step 1: Sort the second array
arr2.sort()
We sort arr2
to enable binary search. After sorting, elements that are close to each other in value will be adjacent, making range queries efficient.
Step 2: Process each element in arr1
For each element x
in arr1
, we need to check if there's any element in arr2
within the range [x - d, x + d]
.
Step 3: Binary search for the lower bound
i = bisect_left(arr2, x - d)
The bisect_left
function finds the leftmost insertion position for x - d
in the sorted arr2
. This gives us the index of the first element that is greater than or equal to x - d
.
Step 4: Check the condition
ans += i == len(arr2) or arr2[i] > x + d
This line checks two conditions:
i == len(arr2)
: This means all elements inarr2
are less thanx - d
. Since the smallest possible element that could violate our condition would bex - d
, and all elements are smaller than this, none of them are within distanced
fromx
.arr2[i] > x + d
: The element at positioni
is the smallest element that is>= x - d
. If this element is also> x + d
, then there's no element in the range[x - d, x + d]
, meaning no element inarr2
is within distanced
fromx
.
If either condition is true, the current element x
from arr1
contributes to the distance value, so we increment our answer.
Time Complexity: O(m log m + n log m)
where n
is the length of arr1
and m
is the length of arr2
. The sorting takes O(m log m)
and we perform n
binary searches, each taking O(log m)
.
Space Complexity: O(1)
if we don't count the space used by the sorting algorithm (which might use O(log m)
for the recursion stack in some implementations).
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 a small example to illustrate the solution approach.
Given:
arr1 = [2, 1, 100]
arr2 = [3, 5, 104]
d = 3
Step 1: Sort arr2
After sorting: arr2 = [3, 5, 104]
(already sorted in this case)
Step 2: Check each element in arr1
For arr1[0] = 2:
- We need to check if any element in arr2 is within range
[2-3, 2+3] = [-1, 5]
- Binary search for
-1
in sorted arr2:bisect_left([3, 5, 104], -1) = 0
(position where -1 would be inserted)- Check: Is
arr2[0] > 5
? arr2[0] = 3
, which is NOT greater than 5- So element 3 is within distance 3 from 2 (|2-3| = 1 ≤ 3)
- This element does NOT count ✗
For arr1[1] = 1:
- We need to check if any element in arr2 is within range
[1-3, 1+3] = [-2, 4]
- Binary search for
-2
in sorted arr2:bisect_left([3, 5, 104], -2) = 0
- Check: Is
arr2[0] > 4
? arr2[0] = 3
, which is NOT greater than 4- So element 3 is within distance 3 from 1 (|1-3| = 2 ≤ 3)
- This element does NOT count ✗
For arr1[2] = 100:
- We need to check if any element in arr2 is within range
[100-3, 100+3] = [97, 103]
- Binary search for
97
in sorted arr2:bisect_left([3, 5, 104], 97) = 2
- Check: Is
arr2[2] > 103
? arr2[2] = 104
, which IS greater than 103- No element in arr2 is within distance 3 from 100
- This element COUNTS ✓
Final Answer: 1 (only the element 100 from arr1 satisfies the condition)
The key insight is that by sorting arr2 and using binary search, we can quickly determine if any element falls within the "forbidden" range [x-d, x+d]
for each element x in arr1. If the binary search either points beyond the array or finds an element outside this range, we know that element x contributes to our distance value.
Solution Implementation
1from typing import List
2from bisect import bisect_left
3
4
5class Solution:
6 def findTheDistanceValue(self, arr1: List[int], arr2: List[int], d: int) -> int:
7 # Sort arr2 to enable binary search
8 arr2.sort()
9
10 # Initialize counter for valid elements
11 distance_value_count = 0
12
13 # Check each element in arr1
14 for num in arr1:
15 # Find the leftmost position where (num - d) could be inserted in arr2
16 # This gives us the index of the smallest element >= (num - d)
17 left_bound_index = bisect_left(arr2, num - d)
18
19 # An element from arr1 is valid if:
20 # 1. left_bound_index == len(arr2): all elements in arr2 are < (num - d)
21 # 2. arr2[left_bound_index] > (num + d): the smallest element >= (num - d) is also > (num + d)
22 # Both conditions mean no element in arr2 is within distance d from num
23 is_valid = (left_bound_index == len(arr2) or arr2[left_bound_index] > num + d)
24 distance_value_count += is_valid
25
26 return distance_value_count
27
1class Solution {
2 public int findTheDistanceValue(int[] arr1, int[] arr2, int d) {
3 // Sort arr2 to enable binary search
4 Arrays.sort(arr2);
5
6 // Counter for elements in arr1 that satisfy the distance condition
7 int count = 0;
8
9 // Check each element in arr1
10 for (int element : arr1) {
11 // Binary search for the smallest element >= (element - d) in arr2
12 // This finds the potential lower bound of the range [element - d, element + d]
13 int searchKey = element - d;
14 int index = Arrays.binarySearch(arr2, searchKey);
15
16 // Convert negative insertion point to actual index
17 // If not found, binarySearch returns (-(insertion point) - 1)
18 // We need the insertion point, which is where the element would be inserted
19 if (index < 0) {
20 index = -index - 1;
21 }
22
23 // Check if there's no element in arr2 within the range [element - d, element + d]
24 // Two conditions for a valid distance value:
25 // 1. index == arr2.length: all elements in arr2 are less than (element - d)
26 // 2. arr2[index] > element + d: the smallest element >= (element - d) is also > (element + d)
27 if (index == arr2.length || arr2[index] > element + d) {
28 count++;
29 }
30 }
31
32 return count;
33 }
34}
35
1class Solution {
2public:
3 int findTheDistanceValue(vector<int>& arr1, vector<int>& arr2, int d) {
4 // Sort arr2 to enable binary search
5 sort(arr2.begin(), arr2.end());
6
7 int count = 0;
8
9 // Check each element in arr1
10 for (int num : arr1) {
11 // Find the first element in arr2 that is >= (num - d)
12 // This gives us the lower bound of the range [num - d, num + d]
13 auto iterator = lower_bound(arr2.begin(), arr2.end(), num - d);
14
15 // If no element exists in arr2 within the range [num - d, num + d],
16 // then this element from arr1 satisfies the distance requirement
17 if (iterator == arr2.end() || *iterator > num + d) {
18 count++;
19 }
20 }
21
22 return count;
23 }
24};
25
1/**
2 * Finds the distance value between two arrays
3 * Distance value is the number of elements in arr1 such that there is no element in arr2
4 * where |arr1[i] - arr2[j]| <= d
5 *
6 * @param arr1 - First array of numbers
7 * @param arr2 - Second array of numbers
8 * @param d - The distance threshold
9 * @returns The count of elements in arr1 that satisfy the distance condition
10 */
11function findTheDistanceValue(arr1: number[], arr2: number[], d: number): number {
12 // Sort arr2 in ascending order for binary search
13 arr2.sort((a, b) => a - b);
14
15 let count: number = 0;
16
17 // Check each element in arr1
18 for (const element of arr1) {
19 // Find the insertion point for (element - d) in sorted arr2
20 // This gives us the index of the first element >= (element - d)
21 const index = binarySearchInsertionPoint(arr2, element - d);
22
23 // If index is at the end of arr2 or the element at index is greater than (element + d),
24 // then no element in arr2 is within distance d of current element
25 if (index === arr2.length || arr2[index] > element + d) {
26 count++;
27 }
28 }
29
30 return count;
31}
32
33/**
34 * Binary search to find the insertion point for a target value in a sorted array
35 * Returns the index where target should be inserted to maintain sorted order
36 *
37 * @param sortedArray - The sorted array to search in
38 * @param target - The value to find insertion point for
39 * @returns The index where target should be inserted
40 */
41function binarySearchInsertionPoint(sortedArray: number[], target: number): number {
42 let left: number = 0;
43 let right: number = sortedArray.length;
44
45 while (left < right) {
46 const mid: number = Math.floor((left + right) / 2);
47
48 if (sortedArray[mid] < target) {
49 left = mid + 1;
50 } else {
51 right = mid;
52 }
53 }
54
55 return left;
56}
57
Time and Space Complexity
The time complexity is O(n log n + m log n)
which simplifies to O((m + n) × log n)
, where m
is the length of arr1
and n
is the length of arr2
.
Breaking down the time complexity:
- Sorting
arr2
takesO(n log n)
time - For each element in
arr1
(m iterations), we perform a binary search usingbisect_left
on the sortedarr2
, which takesO(log n)
time - Total:
O(n log n) + O(m × log n) = O((m + n) × log n)
The space complexity is O(log n)
.
The space complexity comes from:
- The sorting operation on
arr2
usesO(log n)
space for the recursive call stack (assuming Python uses an efficient sorting algorithm like Timsort) - The
bisect_left
function usesO(1)
space since it's implemented iteratively in Python - No additional data structures are created that scale with input size
Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Misunderstanding the Distance Condition
The Problem:
A common mistake is misinterpreting what "distance value" means. Developers often incorrectly count elements from arr1
that have at least one element in arr2
with distance > d, when the correct interpretation requires all elements in arr2
to have distance > d.
Incorrect Implementation:
def findTheDistanceValue(self, arr1: List[int], arr2: List[int], d: int) -> int:
count = 0
for num1 in arr1:
for num2 in arr2:
if abs(num1 - num2) > d: # Wrong! This counts if ANY element satisfies
count += 1
break
return count
Correct Approach:
def findTheDistanceValue(self, arr1: List[int], arr2: List[int], d: int) -> int:
count = 0
for num1 in arr1:
valid = True
for num2 in arr2:
if abs(num1 - num2) <= d: # Check if ANY element violates
valid = False
break
if valid:
count += 1
return count
Pitfall 2: Off-by-One Error in Range Checking
The Problem:
When using binary search, developers might incorrectly check the range boundaries. The condition should be <= d
for violation, not < d
.
Incorrect Implementation:
# Wrong: checking strictly less than d
is_valid = (left_bound_index == len(arr2) or arr2[left_bound_index] >= num + d)
Correct Implementation:
# Correct: an element violates if distance <= d, so we need > d
is_valid = (left_bound_index == len(arr2) or arr2[left_bound_index] > num + d)
Pitfall 3: Not Handling Edge Cases
The Problem: Forgetting to handle edge cases like empty arrays or when all elements satisfy/violate the condition.
Solution: Always test with:
- Empty
arr1
orarr2
- Single element arrays
- Cases where d = 0
- Cases where all elements are valid or invalid
# Edge case examples to test: assert findTheDistanceValue([1], [100], 50) == 0 # Distance exactly at boundary assert findTheDistanceValue([1], [100], 98) == 0 # Just within range assert findTheDistanceValue([1], [100], 99) == 1 # Just outside range assert findTheDistanceValue([], [1, 2, 3], 5) == 0 # Empty arr1
Pitfall 4: Using bisect_right Instead of bisect_left
The Problem:
Using bisect_right
would find the rightmost insertion position, which could lead to missing elements that are exactly equal to num - d
.
Example:
If arr2 = [1, 3, 5, 7]
, num = 5
, and d = 2
:
- Range to check: [3, 7]
bisect_left(arr2, 3)
returns 1 (correct: points to element 3)bisect_right(arr2, 3)
returns 2 (incorrect: skips element 3)
The correct choice is bisect_left
to ensure we don't miss boundary elements.
Which of the following is a good use case for backtracking?
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
Binary Search Speedrun For each of the Speedrun questions you will be given a binary search related problem and a corresponding multiple choice question The multiple choice questions are related to the techniques and template s introduced in the binary search section It's recommended that you have gone through at
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!