Facebook Pixel

1855. Maximum Distance Between a Pair of Values

Problem Description

You are given two integer arrays nums1 and nums2 that are both non-increasing (sorted in descending order or staying the same).

Your task is to find a pair of indices (i, j) where:

  • i is an index from nums1 (where 0 <= i < nums1.length)
  • j is an index from nums2 (where 0 <= j < nums2.length)

For a pair (i, j) to be valid, it must satisfy two conditions:

  1. i <= j (the index in nums1 cannot be greater than the index in nums2)
  2. nums1[i] <= nums2[j] (the value at index i in nums1 must be less than or equal to the value at index j in nums2)

The distance of a valid pair (i, j) is calculated as j - i.

You need to find the maximum distance among all valid pairs. If no valid pairs exist, return 0.

Example of non-increasing array: An array like [5, 4, 4, 2, 1] is non-increasing because each element is less than or equal to the previous one.

The solution uses binary search to efficiently find valid pairs. For each element in nums1 at index i, it searches for the rightmost position in nums2 (starting from index i) where a valid pair can be formed, maximizing the distance j - i.

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

Intuition

Since both arrays are non-increasing (sorted in descending order), we can leverage this property to efficiently find valid pairs.

For each element nums1[i], we want to find the farthest valid index j in nums2 such that nums1[i] <= nums2[j] and i <= j. To maximize the distance j - i, we need to find the largest possible j.

Because nums2 is non-increasing, once we find a position where nums1[i] > nums2[j], all positions after j will also fail the condition nums1[i] <= nums2[j]. This monotonic property makes binary search a perfect fit.

The key insight is understanding the boolean pattern. For a fixed nums1[i], as we scan through nums2 from left to right starting at index i, the condition nums2[j] >= nums1[i] creates a pattern like:

true, true, true, false, false, false, ...

Since we want the last true (the rightmost valid j), we can reformulate: find the first index where nums2[j] < nums1[i] (i.e., the condition becomes invalid), then subtract 1 to get the last valid position.

This transforms our problem into the standard binary search template of finding the first true index, where feasible(j) = (nums2[j] < nums1[i]).

By iterating through each element in nums1 and finding the optimal pairing in nums2 using binary search, we achieve an efficient O(m * log n) solution instead of the brute force O(m * n) approach.

Learn more about Two Pointers and Binary Search patterns.

Solution Implementation

1from typing import List
2
3
4class Solution:
5    def maxDistance(self, nums1: List[int], nums2: List[int]) -> int:
6        """
7        Find the maximum distance j - i where i <= j and nums1[i] <= nums2[j].
8
9        Args:
10            nums1: First list of integers (non-increasing order)
11            nums2: Second list of integers (non-increasing order)
12
13        Returns:
14            Maximum distance between valid index pairs
15        """
16        max_distance = 0
17        n2 = len(nums2)
18
19        for i, value in enumerate(nums1):
20            # Binary search to find the first index j where nums2[j] < value
21            # This uses the standard template: find first true index
22            left, right = i, n2 - 1
23            first_true_index = -1
24
25            while left <= right:
26                mid = (left + right) // 2
27                if nums2[mid] < value:  # feasible condition: pair becomes invalid
28                    first_true_index = mid
29                    right = mid - 1
30                else:
31                    left = mid + 1
32
33            # Calculate the last valid j
34            if first_true_index == -1:
35                # All positions from i to end are valid
36                last_valid_j = n2 - 1
37            else:
38                # Last valid position is one before first invalid
39                last_valid_j = first_true_index - 1
40
41            # Update maximum distance if valid pair exists
42            if last_valid_j >= i:
43                max_distance = max(max_distance, last_valid_j - i)
44
45        return max_distance
46
1class Solution {
2    /**
3     * Finds the maximum distance between two indices i and j where:
4     * - i <= j
5     * - nums1[i] <= nums2[j]
6     * - distance = j - i
7     *
8     * @param nums1 First non-increasing array
9     * @param nums2 Second non-increasing array
10     * @return Maximum distance between valid pairs
11     */
12    public int maxDistance(int[] nums1, int[] nums2) {
13        int maxDistance = 0;
14        int n1 = nums1.length;
15        int n2 = nums2.length;
16
17        for (int i = 0; i < n1; i++) {
18            int value = nums1[i];
19
20            // Binary search to find the first index j where nums2[j] < value
21            // Using the standard template: find first true index
22            int left = i;
23            int right = n2 - 1;
24            int firstTrueIndex = -1;
25
26            while (left <= right) {
27                int mid = left + (right - left) / 2;
28                if (nums2[mid] < value) {  // feasible condition: pair becomes invalid
29                    firstTrueIndex = mid;
30                    right = mid - 1;
31                } else {
32                    left = mid + 1;
33                }
34            }
35
36            // Calculate the last valid j
37            int lastValidJ;
38            if (firstTrueIndex == -1) {
39                // All positions from i to end are valid
40                lastValidJ = n2 - 1;
41            } else {
42                // Last valid position is one before first invalid
43                lastValidJ = firstTrueIndex - 1;
44            }
45
46            // Update maximum distance if valid pair exists
47            if (lastValidJ >= i) {
48                maxDistance = Math.max(maxDistance, lastValidJ - i);
49            }
50        }
51
52        return maxDistance;
53    }
54}
55
1class Solution {
2public:
3    int maxDistance(vector<int>& nums1, vector<int>& nums2) {
4        int maxDist = 0;
5        int n1 = nums1.size();
6        int n2 = nums2.size();
7
8        for (int i = 0; i < n1; ++i) {
9            int value = nums1[i];
10
11            // Binary search to find the first index j where nums2[j] < value
12            // Using the standard template: find first true index
13            int left = i;
14            int right = n2 - 1;
15            int firstTrueIndex = -1;
16
17            while (left <= right) {
18                int mid = left + (right - left) / 2;
19                if (nums2[mid] < value) {  // feasible condition: pair becomes invalid
20                    firstTrueIndex = mid;
21                    right = mid - 1;
22                } else {
23                    left = mid + 1;
24                }
25            }
26
27            // Calculate the last valid j
28            int lastValidJ;
29            if (firstTrueIndex == -1) {
30                // All positions from i to end are valid
31                lastValidJ = n2 - 1;
32            } else {
33                // Last valid position is one before first invalid
34                lastValidJ = firstTrueIndex - 1;
35            }
36
37            // Update maximum distance if valid pair exists
38            if (lastValidJ >= i) {
39                maxDist = max(maxDist, lastValidJ - i);
40            }
41        }
42
43        return maxDist;
44    }
45};
46
1/**
2 * Finds the maximum distance between valid index pairs (i, j) where:
3 * - i <= j
4 * - nums1[i] <= nums2[j]
5 * The distance is defined as j - i
6 *
7 * @param nums1 - First non-increasing array
8 * @param nums2 - Second non-increasing array
9 * @returns The maximum distance between valid pairs
10 */
11function maxDistance(nums1: number[], nums2: number[]): number {
12    let maxDistanceFound: number = 0;
13    const n1: number = nums1.length;
14    const n2: number = nums2.length;
15
16    for (let i = 0; i < n1; i++) {
17        const value: number = nums1[i];
18
19        // Binary search to find the first index j where nums2[j] < value
20        // Using the standard template: find first true index
21        let left: number = i;
22        let right: number = n2 - 1;
23        let firstTrueIndex: number = -1;
24
25        while (left <= right) {
26            const mid: number = Math.floor((left + right) / 2);
27            if (nums2[mid] < value) {  // feasible condition: pair becomes invalid
28                firstTrueIndex = mid;
29                right = mid - 1;
30            } else {
31                left = mid + 1;
32            }
33        }
34
35        // Calculate the last valid j
36        let lastValidJ: number;
37        if (firstTrueIndex === -1) {
38            // All positions from i to end are valid
39            lastValidJ = n2 - 1;
40        } else {
41            // Last valid position is one before first invalid
42            lastValidJ = firstTrueIndex - 1;
43        }
44
45        // Update maximum distance if valid pair exists
46        if (lastValidJ >= i) {
47            maxDistanceFound = Math.max(maxDistanceFound, lastValidJ - i);
48        }
49    }
50
51    return maxDistanceFound;
52}
53

Solution Approach

The solution uses binary search to efficiently find the maximum distance between valid pairs.

Step-by-step Implementation:

  1. Initialize the answer: Start with max_distance = 0 to track the maximum distance found.

  2. Iterate through nums1: For each element nums1[i]:

  3. Binary search in nums2: For each nums1[i], we search in nums2 starting from index i to find the first position where nums2[j] < nums1[i]. The last valid position is then j - 1.

  4. Apply the template: Using the standard binary search template:

    left, right = i, len(nums2) - 1
    first_true_index = -1
    
    while left <= right:
        mid = (left + right) // 2
        if nums2[mid] < nums1[i]:  # feasible condition
            first_true_index = mid
            right = mid - 1
        else:
            left = mid + 1
    • The feasible condition nums2[mid] < nums1[i] finds the first index where the pair becomes invalid
    • If first_true_index != -1, the last valid j is first_true_index - 1
    • If first_true_index == -1, all positions from i to end are valid, so last valid j is len(nums2) - 1
  5. Calculate distance and update maximum:

    • Compute the distance as j - i where j is the last valid position
    • Update max_distance with the maximum of current max_distance and the new distance
    • Only update if j >= i (valid pair condition)
  6. Return the result: After checking all elements in nums1, return the maximum distance found.

Time Complexity: O(m * log n) where m is the length of nums1 and n is the length of nums2. We perform a binary search (O(log n)) for each element in nums1.

Space Complexity: O(1) as we only use a constant amount of extra space.

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 concrete example to understand how the solution works.

Given:

  • nums1 = [10, 8, 2] (non-increasing)
  • nums2 = [12, 11, 8, 5, 2] (non-increasing)

Step 1: Initialize

  • max_distance = 0

Step 2: Process each element in nums1

For i = 0, nums1[0] = 10:

  • Search range: left = 0, right = 4
  • Find first j where nums2[j] < 10
  • Binary search:
    • mid = 2: nums2[2] = 8 < 10 ✓ → first_true_index = 2, right = 1
    • mid = 0: nums2[0] = 12 >= 10left = 1
    • mid = 1: nums2[1] = 11 >= 10left = 2
    • Loop ends with first_true_index = 2
  • Last valid j = first_true_index - 1 = 1
  • Verify: nums2[1] = 11 >= 10
  • Distance = 1 - 0 = 1
  • Update max_distance = max(0, 1) = 1

For i = 1, nums1[1] = 8:

  • Search range: left = 1, right = 4
  • Find first j where nums2[j] < 8
  • Binary search:
    • mid = 2: nums2[2] = 8 >= 8left = 3
    • mid = 3: nums2[3] = 5 < 8 ✓ → first_true_index = 3, right = 2
    • Loop ends with first_true_index = 3
  • Last valid j = first_true_index - 1 = 2
  • Verify: nums2[2] = 8 >= 8
  • Distance = 2 - 1 = 1
  • Update max_distance = max(1, 1) = 1

For i = 2, nums1[2] = 2:

  • Search range: left = 2, right = 4
  • Find first j where nums2[j] < 2
  • Binary search:
    • mid = 3: nums2[3] = 5 >= 2left = 4
    • mid = 4: nums2[4] = 2 >= 2left = 5
    • Loop ends with first_true_index = -1 (no j where nums2[j] < 2)
  • All positions valid, so last valid j = len(nums2) - 1 = 4
  • Verify: nums2[4] = 2 >= 2
  • Distance = 4 - 2 = 2
  • Update max_distance = max(1, 2) = 2

Result: The maximum distance is 2, achieved by the pair (i=2, j=4) where nums1[2] = 2 and nums2[4] = 2.

The binary search template efficiently finds the first invalid position, from which we derive the last valid position.

Time and Space Complexity

The time complexity is O(m × log n), where m is the length of nums1 and n is the length of nums2. This is because:

  • The code iterates through each element in nums1 (which takes O(m) time)
  • For each element, it performs a binary search in nums2 (which takes O(log n) time per search)
  • Therefore, the total time complexity is O(m × log n)

The space complexity is O(1) as the algorithm only uses a constant amount of extra space for variables like left, right, mid, first_true_index, last_valid_j, and max_distance, regardless of the input size.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Using the wrong binary search template variant

A common mistake is using while left < right with right = mid instead of the standard template.

Wrong approach:

while left < right:
    mid = (left + right) // 2
    if nums2[mid] < value:
        right = mid
    else:
        left = mid + 1
return left - 1  # Error-prone calculation

Correct approach (using the standard template):

first_true_index = -1
while left <= right:
    mid = (left + right) // 2
    if nums2[mid] < value:
        first_true_index = mid
        right = mid - 1
    else:
        left = mid + 1
# last_valid_j = first_true_index - 1 if found, else n2 - 1

2. Forgetting to handle when no invalid position exists

When all positions from i to the end are valid (all nums2[j] >= nums1[i]), first_true_index remains -1.

Pitfall:

# Wrong: directly using first_true_index - 1
last_valid_j = first_true_index - 1  # Returns -2 when first_true_index is -1!

Solution: Always check if first_true_index == -1:

if first_true_index == -1:
    last_valid_j = n2 - 1  # All positions valid
else:
    last_valid_j = first_true_index - 1

3. Not validating that j >= i before calculating distance

The constraint requires i <= j, but after binary search, last_valid_j might be less than i.

Pitfall:

# Wrong: not checking if j >= i
max_distance = max(max_distance, last_valid_j - i)  # Could add negative distance

Solution: Always check the valid pair condition:

if last_valid_j >= i:
    max_distance = max(max_distance, last_valid_j - i)

4. Starting the search range from 0 instead of i

The problem requires i <= j, so the search should start from index i, not 0.

Pitfall:

# Wrong: searching from index 0
left, right = 0, n2 - 1  # May find j < i

Solution: Start from index i:

left, right = i, n2 - 1  # Ensures j >= i
Loading...
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which of the following uses divide and conquer strategy?


Recommended Readings

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

Load More