Find Indices With Index and Value Difference II
MedPrompt
You are given a 0-indexed integer array nums having length n, an integer indexDifference, and an integer valueDifference.
Your task is to find two indices i and j, both in the range [0, n - 1], that satisfy the following conditions:
abs(i - j) >= indexDifference, andabs(nums[i] - nums[j]) >= valueDifference
Return an integer array answer, where answer = [i, j] if there are two such indices, and answer = [-1, -1] otherwise. If there are multiple choices for the two indices, return any of them.
Note: i and j may be equal.
Example 1:
Input: nums = [5,1,4,1], indexDifference = 2, valueDifference = 4
Output: [0,3]
Explanation: In this example, i = 0 and j = 3 can be selected.
abs(0 - 3) >= 2 and abs(nums[0] - nums[3]) >= 4.
Hence, a valid answer is [0,3].
[3,0] is also a valid answer.Example 2:
Input: nums = [2,1], indexDifference = 0, valueDifference = 0
Output: [0,0]
Explanation: In this example, i = 0 and j = 0 can be selected.
abs(0 - 0) >= 0 and abs(nums[0] - nums[0]) >= 0.
Hence, a valid answer is [0,0].
Other valid answers are [0,1], [1,0], and [1,1].Example 3:
Input: nums = [1,2,3], indexDifference = 2, valueDifference = 4
Output: [-1,-1]
Explanation: In this example, it can be shown that it is impossible to find two indices that satisfy both conditions.
Hence, [-1,-1] is returned.
Constraints:
1 <= n == nums.length <= 1050 <= nums[i] <= 1090 <= indexDifference <= 1050 <= valueDifference <= 109
Approaches
2 approaches with complexity analysis and trade-offs.
This approach involves checking every possible pair of indices (i, j) in the array. For each pair, we verify if it satisfies both the indexDifference and valueDifference conditions.
Algorithm
- Get the length of the array,
n. - Iterate through the array with an index
ifrom0ton-1. - Inside the first loop, iterate through the array with an index
jfrom0ton-1. - For each pair
(i, j), check ifabs(i - j) >= indexDifference. - If the index difference condition is met, check if
abs(nums[i] - nums[j]) >= valueDifference. - If both conditions are true, return the pair
[i, j]. - If the loops finish without returning, it means no valid pair was found. Return
[-1, -1].
Walkthrough
We use two nested loops to generate all pairs of indices (i, j). The outer loop iterates i from 0 to n-1, and the inner loop iterates j from 0 to n-1. Inside the inner loop, we check two conditions: abs(i - j) >= indexDifference and abs(nums[i] - nums[j]) >= valueDifference. If both conditions are met, we have found a valid pair, and we can immediately return [i, j]. If the loops complete without finding any such pair, it means no solution exists, and we return [-1, -1]. This method is straightforward but inefficient for large inputs due to its quadratic time complexity.
class Solution { public int[] findIndices(int[] nums, int indexDifference, int valueDifference) { int n = nums.length; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (Math.abs(i - j) >= indexDifference && Math.abs(nums[i] - nums[j]) >= valueDifference) { return new int[]{i, j}; } } } return new int[]{-1, -1}; }}Complexity
Time
O(n^2), where `n` is the number of elements in `nums`. The nested loops iterate through all `n*n` pairs of indices.
Space
O(1), as we only use a constant amount of extra space for variables.
Trade-offs
Pros
Simple to understand and implement.
Correctly solves the problem for small inputs.
Cons
Highly inefficient for large arrays.
Time complexity of O(n^2) will lead to a 'Time Limit Exceeded' error on platforms with large test cases.
This optimized approach avoids the nested loops by iterating through the array just once. For each element, it efficiently checks for a valid partner by keeping track of the minimum and maximum values seen so far in the valid preceding part of the array.
Algorithm
- Initialize
minIdx = 0andmaxIdx = 0to track the indices of the minimum and maximum values. - Iterate with an index
jfromindexDifferenceton-1. - Let
i = j - indexDifference. Thisiis the latest index that can be paired withj. - Update
minIdxandmaxIdxbased onnums[i]. The range for finding min/max is[0, i].- If
nums[i] < nums[minIdx], updateminIdx = i. - If
nums[i] > nums[maxIdx], updatemaxIdx = i.
- If
- Now, check if
nums[j]can form a valid pair with the historical min or max.- Check with the minimum value found so far: if
nums[j] - nums[minIdx] >= valueDifference, return[minIdx, j]. - Check with the maximum value found so far: if
nums[maxIdx] - nums[j] >= valueDifference, return[maxIdx, j].
- Check with the minimum value found so far: if
- If the loop completes without finding a pair, return
[-1, -1].
Walkthrough
The core idea is to rephrase the problem: for each index j, we need to find an index i such that i <= j - indexDifference and abs(nums[i] - nums[j]) >= valueDifference. The second condition means we need an i where nums[i] is either very small (<= nums[j] - valueDifference) or very large (>= nums[j] + valueDifference).
To find such an i efficiently, as we iterate j from indexDifference to n-1, we can maintain the minimum and maximum values in the prefix nums[0...j - indexDifference]. We can do this in a single pass. In each iteration, we first update our knowledge of the minimum and maximum values in the valid prefix. The new element to consider for the prefix is at index i = j - indexDifference. We update the indices of the running minimum (minIdx) and maximum (maxIdx) seen so far. After updating, minIdx and maxIdx point to the minimum and maximum values in the range [0, j - indexDifference]. We then check if nums[j] can form a valid pair with nums[minIdx] or nums[maxIdx]. If a pair is found, we return it. If the loop finishes, no such pair exists.
class Solution { public int[] findIndices(int[] nums, int indexDifference, int valueDifference) { int n = nums.length; int minIdx = 0; int maxIdx = 0; for (int j = indexDifference; j < n; j++) { int i = j - indexDifference; // Update min and max indices from the valid range [0, i] if (nums[i] < nums[minIdx]) { minIdx = i; } if (nums[i] > nums[maxIdx]) { maxIdx = i; } // Check if the current element nums[j] satisfies the valueDifference // with the min or max element found so far. if (nums[j] - nums[minIdx] >= valueDifference) { return new int[]{minIdx, j}; } if (nums[maxIdx] - nums[j] >= valueDifference) { return new int[]{maxIdx, j}; } } return new int[]{-1, -1}; }}Complexity
Time
O(n), where `n` is the number of elements in `nums`. We perform a single pass through the array.
Space
O(1), as we only use a few variables to store indices, regardless of the input size.
Trade-offs
Pros
Highly efficient with a linear time complexity.
Optimal solution for the given constraints.
Uses constant extra space.
Cons
The logic is slightly more complex to reason about compared to the brute-force approach.
Solutions
Solution
class Solution {public int[] findIndices(int[] nums, int indexDifference, int valueDifference) { int mi = 0; int mx = 0; for (int i = indexDifference; i < nums.length; ++i) { int j = i - indexDifference; if (nums[j] < nums[mi]) { mi = j; } if (nums[j] > nums[mx]) { mx = j; } if (nums[i] - nums[mi] >= valueDifference) { return new int[]{mi, i}; } if (nums[mx] - nums[i] >= valueDifference) { return new int[]{mx, i}; } } return new int[]{-1, -1}; }}class Solution {public: vector<int> findIndices(vector<int> &nums, int indexDifference, int valueDifference) { int mi = 0, mx = 0; for (int i = indexDifference; i < nums.size(); ++i) { int j = i - indexDifference; if (nums[j] < nums[mi]) { mi = j; } if (nums[j] > nums[mx]) { mx = j; } if (nums[i] - nums[mi] >= valueDifference) { return {mi, i}; } if (nums[mx] - nums[i] >= valueDifference) { return {mx, i}; } } return {-1, -1}; }};class Solution: def findIndices(self, nums: List[int], indexDifference: int, valueDifference: int) -> List[int]: mi = mx = 0 for i in range(indexDifference, len(nums)): j = i - indexDifference if nums[j] < nums[mi]: mi = j if nums[j] > nums[mx]: mx = j if nums[i] - nums[mi] >= valueDifference: return [mi, i] if nums[mx] - nums[i] >= valueDifference: return [mx, i] return [- 1, - 1]Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.