Minimum Absolute Difference Between Elements With Constraint
MedPrompt
You are given a 0-indexed integer array nums and an integer x.
Find the minimum absolute difference between two elements in the array that are at least x indices apart.
In other words, find two indices i and j such that abs(i - j) >= x and abs(nums[i] - nums[j]) is minimized.
Return an integer denoting the minimum absolute difference between two elements that are at least x indices apart.
Example 1:
Input: nums = [4,3,2,4], x = 2
Output: 0
Explanation: We can select nums[0] = 4 and nums[3] = 4.
They are at least 2 indices apart, and their absolute difference is the minimum, 0.
It can be shown that 0 is the optimal answer.Example 2:
Input: nums = [5,3,2,10,15], x = 1
Output: 1
Explanation: We can select nums[1] = 3 and nums[2] = 2.
They are at least 1 index apart, and their absolute difference is the minimum, 1.
It can be shown that 1 is the optimal answer.Example 3:
Input: nums = [1,2,3,4], x = 3
Output: 3
Explanation: We can select nums[0] = 1 and nums[3] = 4.
They are at least 3 indices apart, and their absolute difference is the minimum, 3.
It can be shown that 3 is the optimal answer.
Constraints:
1 <= nums.length <= 1051 <= nums[i] <= 1090 <= x < nums.length
Approaches
2 approaches with complexity analysis and trade-offs.
This approach directly translates the problem statement into code. We check every possible pair of indices (i, j) that satisfies the condition abs(i - j) >= x. For each valid pair, we calculate the absolute difference of the corresponding elements and keep track of the minimum difference found.
Algorithm
- Initialize a variable
minDifferencetoInteger.MAX_VALUE. - Get the length of the array,
n. - Loop for
ifrom0ton - 1. - Inside this loop, start another loop for
jfromi + xton - 1. - This ensures that for any pair of indices
(i, j), the conditionj - i >= xis always met. - Calculate
currentDifference = abs(nums[i] - nums[j]). - Update
minDifference = min(minDifference, currentDifference). - After both loops complete, return
minDifference.
Walkthrough
The core idea is to check every pair of indices (i, j) that satisfies the distance constraint abs(i - j) >= x and find the minimum difference abs(nums[i] - nums[j]).
- Initialize a variable
minDifferenceto a very large value, likeInteger.MAX_VALUE. - Use two nested loops. The outer loop iterates
ifrom0ton-1. - The inner loop iterates
jfromi + xton-1. This setup ensures that for any pair(i, j), the conditionj - i >= xholds, which impliesabs(j - i) >= x. - Inside the inner loop, calculate the absolute difference between
nums.get(i)andnums.get(j). - Compare this difference with
minDifferenceand updateminDifferenceif the new difference is smaller. - After the loops complete,
minDifferencewill contain the result.
Here is the Java implementation:
import java.util.List; class Solution { public int minAbsoluteDifference(List<Integer> nums, int x) { int minDifference = Integer.MAX_VALUE; int n = nums.size(); for (int i = 0; i < n; i++) { for (int j = i + x; j < n; j++) { int diff = Math.abs(nums.get(i) - nums.get(j)); minDifference = Math.min(minDifference, diff); } } return minDifference; }}Complexity
Time
O(n^2), where `n` is the number of elements in `nums`. The nested loops lead to a quadratic number of comparisons in the worst case (when `x` is small).
Space
O(1), as we only use a constant amount of extra space for variables.
Trade-offs
Pros
Simple to understand and implement.
Uses constant extra space.
Cons
Highly inefficient for large inputs due to its quadratic time complexity.
Will likely result in a 'Time Limit Exceeded' error on platforms with strict time limits for the given constraints.
A more efficient approach involves iterating through the array while maintaining a sorted collection of elements that are eligible for comparison. For each element nums[i], we need to find the closest value among elements nums[j] where j <= i - x. This can be done efficiently by using a balanced binary search tree (like Java's TreeSet) to store the elements from the "past" window nums[0...i-x].
Algorithm
- If
xis 0, the answer is 0, so we can return immediately. - Initialize
minDifferencetoInteger.MAX_VALUE. - Create a
TreeSet<Integer>namedbstto store elements from the valid 'past' window. - Loop for
ifromxton - 1. - In each iteration, add the element
nums[i - x]to thebst. This element is now part of the set of candidates for comparison. - For the current element
nums[i], find its closest neighbors in thebst:- Find the
floorofnums[i]: the largest element inbstthat is less than or equal tonums[i]. - Find the
ceilingofnums[i]: the smallest element inbstthat is greater than or equal tonums[i].
- Find the
- If a
floorelement exists, calculatediff = nums[i] - floorand updateminDifference. - If a
ceilingelement exists, calculatediff = ceiling - nums[i]and updateminDifference. - After the loop, return
minDifference.
Walkthrough
This optimized approach avoids redundant comparisons by using a data structure that keeps track of potential candidate elements in a sorted manner. We can iterate through the array and for each element nums[i], efficiently find the closest value among the elements that are at least x indices before it. A balanced binary search tree, implemented as TreeSet in Java, is perfect for this task.
The algorithm proceeds as follows:
- We iterate with an index
ifromxton-1. For eachnums[i], we need to find a matchingnums[j]wherej <= i - x. - We maintain a
TreeSetthat stores the elements from the "past" window, i.e.,{nums[0], nums[1], ..., nums[i-x]}. - In each iteration
i, we first addnums.get(i-x)to theTreeSet. This makes it available for comparison withnums.get(i)and all subsequent elements. - Then, for the current element
nums.get(i), we search in theTreeSetfor the two values that are closest to it:- The largest element in the set that is less than or equal to
nums.get(i). This is found using thefloor()method. - The smallest element in the set that is greater than or equal to
nums.get(i). This is found using theceiling()method.
- The largest element in the set that is less than or equal to
- We calculate the absolute difference between
nums.get(i)and both thefloorandceiling(if they exist) and update our overallminDifference.
This way, for each element, we only perform a logarithmic time search instead of a linear scan.
Here is the Java implementation:
import java.util.List;import java.util.TreeSet; class Solution { public int minAbsoluteDifference(List<Integer> nums, int x) { if (x == 0) { return 0; } int minDifference = Integer.MAX_VALUE; int n = nums.size(); TreeSet<Integer> bst = new TreeSet<>(); for (int i = x; i < n; i++) { bst.add(nums.get(i - x)); Integer currentNum = nums.get(i); // Find the greatest element <= currentNum Integer floor = bst.floor(currentNum); if (floor != null) { minDifference = Math.min(minDifference, currentNum - floor); } // Find the smallest element >= currentNum Integer ceiling = bst.ceiling(currentNum); if (ceiling != null) { minDifference = Math.min(minDifference, ceiling - currentNum); } } return minDifference; }}Complexity
Time
O(n log n), where `n` is the number of elements in `nums`. The main loop runs `n - x` times. Inside the loop, `add`, `floor`, and `ceiling` operations on the `TreeSet` take O(log k) time, where `k` is the size of the set. The size `k` grows up to `n - x`. Therefore, the total time complexity is dominated by these operations, resulting in O((n-x) * log(n-x)), which simplifies to O(n log n).
Space
O(n). In the worst case (when `x` is small), the `TreeSet` can store up to `n - x` elements, leading to a space complexity of O(n).
Trade-offs
Pros
Significantly more efficient than the brute-force approach.
Handles large inputs within typical time limits.
Relatively straightforward to implement using standard library data structures.
Cons
Requires more memory than the brute-force approach due to the
TreeSet.
Solutions
Solution
class Solution {public int minAbsoluteDifference(List<Integer> nums, int x) { TreeMap<Integer, Integer> tm = new TreeMap<>(); int ans = 1 << 30; for (int i = x; i < nums.size(); ++i) { tm.merge(nums.get(i - x), 1, Integer : : sum); Integer key = tm.ceilingKey(nums.get(i)); if (key != null) { ans = Math.min(ans, key - nums.get(i)); } key = tm.floorKey(nums.get(i)); if (key != null) { ans = Math.min(ans, nums.get(i) - key); } } return ans; }}from sortedcontainers import SortedList class Solution : def minAbsoluteDifference ( self , nums : List [ int ], x : int ) -> int : sl = SortedList () ans = inf for i in range ( x , len ( nums )): sl . add ( nums [ i - x ]) j = bisect_left ( sl , nums [ i ]) if j < len ( sl ): ans = min ( ans , sl [ j ] - nums [ i ]) if j : ans = min ( ans , nums [ i ] - sl [ j - 1 ]) return ansclass Solution {public: int minAbsoluteDifference(vector<int> &nums, int x) { int ans = 1 << 30; multiset<int> s; for (int i = x; i < nums.size(); ++i) { s.insert(nums[i - x]); auto it = s.lower_bound(nums[i]); if (it != s.end()) { ans = min(ans, *it - nums[i]); } if (it != s.begin()) { --it; ans = min(ans, nums[i] - *it); } } return ans; }};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.