Facebook Pixel

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], and d = 2
  • For arr1[0] = 4: Check against all elements in arr2
    • |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.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

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 in arr2 are less than x - d. Since the smallest possible element that could violate our condition would be x - d, and all elements are smaller than this, none of them are within distance d from x.
  • arr2[i] > x + d: The element at position i 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 in arr2 is within distance d from x.

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 Evaluator

Example 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 takes O(n log n) time
  • For each element in arr1 (m iterations), we perform a binary search using bisect_left on the sorted arr2, which takes O(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 uses O(log n) space for the recursive call stack (assuming Python uses an efficient sorting algorithm like Timsort)
  • The bisect_left function uses O(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 or arr2
  • 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.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which of the following is a good use case for backtracking?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More