- What if you fix an index in
nums1and try to find the rightmost valid index innums2? - Both arrays are non-increasing. Can you leverage this property for efficient search?
- Is there a way to avoid checking every possible pair?
- For each index
iinnums1, how do you efficiently find the largestjinnums2such thatnums1[i] <= nums2[j]andi <= j?
Try binary search or two pointers in sorted array to avoid brute force.
- Can you process both arrays in a single pass?
Try to use two pointers to move forward only when the condition is met.
For each i, you want the rightmost j (with i <= j) such that nums1[i] <= nums2[j].
The problem is a classic two pointers or binary search on sorted arrays pattern. Due to the sorted nature, this is perfect for:
- Binary search: To find the rightmost
jfor eachiin logarithmic time. - Two pointers: Since both arrays are non-increasing, for each
i, the validj(wherenums1[i] <= nums2[j]) is monotonic: asiincreases, the possiblejdoes not decrease.
Give the first number nums1[i], there are three cases below, and we're looking for the last number nums2[j] that satisfies the condition: nums1[i] <= nums2[j].
nums1[i]
// in nums2
|------------|--------------|-------------|
> nums1[i] == nums1[i] ^ < nums1[i]
|
* The last number that satisfies the conditionWe can iterate through nums1 and use binary search to find the upper bound of nums1[i] in nums2, that is to find the last index j in nums2 such that nums2[j] >= nums1[i] and j >= i. This leverages the non-increasing order of both arrays.
fun maxDistance(nums1: IntArray, nums2: IntArray): Int {
var maxDistance = 0
for (i in nums1.indices) {
val j = upperBound(nums2, nums1[i])
if (j - i > 0) {
maxDistance = maxOf(maxDistance, j - i)
}
}
return maxDistance
}
/**
* Search for the last element s.t. target <= nums[j] (nums1[i] <= nums2[j]).
*/
private fun upperBound(nums: IntArray, target: Int): Int {
var left = 0
var right = nums.size - 1
while (left <= right) {
val middle = left + (right - left) / 2
val feasible = target <= nums[middle]
if (feasible) {
left = middle + 1
} else {
right = middle - 1
}
}
return right
}- Time Complexity:
O(m log n)wheremis the length ofnums1andnis the length ofnums2. - Space Complexity:
O(1)
For each i:
- As long as the condition
nums1[i] <= nums2[j]is met, we can movejas far as possible. We update the answer with the maximum distance whilejis moving. (The first implementation) Or we can movejto the rightmost position until the condition is not met, then update the answer. (The second implementation) - If the condition is not met, we move
ito the next position.
fun maxDistance(nums1: IntArray, nums2: IntArray): Int {
val n = nums2.size
var j = 0
var maxDistance = 0
for (i in nums1.indices) {
while (j < n && nums1[i] <= nums2[j]) {
j++
}
maxDistance = maxOf(maxDistance, j - 1 - i)
}
return maxDistance
}
// Or equivalently
fun maxDistance(nums1: IntArray, nums2: IntArray): Int {
val m = nums1.size
val n = nums2.size
var i = 0
var j = 0
var maxDistance = 0
while (i < m && j < n) {
val first = nums1[i]
val second = nums2[j]
if (first <= second) {
maxDistance = maxOf(maxDistance, j - i)
j++
} else {
i++
}
}
return maxDistance
}- Time Complexity:
O(m + n) - Space Complexity:
O(1)
nums1ornums2has only one element.- All elements in
nums1are greater than those innums2(should return 0). - All elements in
nums1are less than or equal to those innums2(should return the largest possible distance). - The valid pair is only at the start or end of the arrays.
- Arrays with duplicate values.
- Forgetting to check
j >= i(the problem requiresi <= j). - Not handling the case when no valid
jexists for a giveni(should not update the answer in this case).