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:
iis an index fromnums1(where0 <= i < nums1.length)jis an index fromnums2(where0 <= j < nums2.length)
For a pair (i, j) to be valid, it must satisfy two conditions:
i <= j(the index innums1cannot be greater than the index innums2)nums1[i] <= nums2[j](the value at indexiinnums1must be less than or equal to the value at indexjinnums2)
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.
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
461class 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}
551class 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};
461/**
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}
53Solution Approach
The solution uses binary search to efficiently find the maximum distance between valid pairs.
Step-by-step Implementation:
-
Initialize the answer: Start with
max_distance = 0to track the maximum distance found. -
Iterate through nums1: For each element
nums1[i]: -
Binary search in nums2: For each
nums1[i], we search innums2starting from indexito find the first position wherenums2[j] < nums1[i]. The last valid position is thenj - 1. -
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 isfirst_true_index - 1 - If
first_true_index == -1, all positions from i to end are valid, so last valid j islen(nums2) - 1
- The feasible condition
-
Calculate distance and update maximum:
- Compute the distance as
j - iwhere j is the last valid position - Update
max_distancewith the maximum of currentmax_distanceand the new distance - Only update if
j >= i(valid pair condition)
- Compute the distance as
-
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 EvaluatorExample 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 = 1mid = 0:nums2[0] = 12 >= 10→left = 1mid = 1:nums2[1] = 11 >= 10→left = 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 >= 8→left = 3mid = 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 >= 2→left = 4mid = 4:nums2[4] = 2 >= 2→left = 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 takesO(m)time) - For each element, it performs a binary search in
nums2(which takesO(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
Which of the following uses divide and conquer strategy?
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
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Don’t Miss This!