Talentd
FleetCode
Make and follow sheets.Sign in

Minimum Absolute Difference Between Elements With Constraint solution and explanation

MediumArrayBinary SearchOrdered Set13 min read38.0% acceptanceUpdated 9 Apr 2026
2817. Minimum Absolute Difference Between Elements With Constraint (Leetcode Medium)Programming Live with Larry · 6:43 · 2K viewsWatch on YouTube
9 more videos on this problem
  1. 2817. Minimum Absolute Difference Between Elements With Constraint (Leetcode Medium)Programming Live with Larry · 6:43 · 2K views
  2. Leetcode Weekly contest 358 - Medium - Minimum Absolute Difference Between Elements With ConstraintPrakhar Agrawal · 10:29 · 2K views
  3. Leetcode Weekly contest 358 | Minimum Absolute Difference Between Elements With Constraint | HindiPawan Kumar Giri · 17:38 · 2K views
  4. Leetcode 2817 Minimum Absolute Difference Between Elements With Constraint HindiThinkCode · 13:02 · 1K views
  5. Minimum Absolute Difference Between Elements With Constraint - LEETCODE WEEKLY CONTEST 358Joyjit Codes · 10:02 · 966 views
  6. [Eng] Leetcode Weekly Contest 358 |2817 Minimum Absolute Difference Between Elements With ConstraintCyCode · 12:18 · 891 views
  7. Leetcode 2817 Minimum Absolute Difference Between Elements With ConstraintSandip Jana · 15:01 · 759 views
  8. Minimum Absolute Difference Between Elements With Constraint | Weekly-contest-358Rohit Satpute · 8:26 · 748 views
  9. Leetcode 2817. Minimum Absolute Difference Between Elements With ConstraintElite Code · 22:56 · 742 views
  10. minimum absolute difference between elements with constraint #leetcodechallengecrazy developers · 0:23 · 720 views

The problem

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 <= 105
  • 1 <= nums[i] <= 109
  • 0 <= x < nums.length

Approach overview

Problem Overview: You are given an integer array nums and an integer x. The goal is to find the minimum absolute difference between two elements nums[i] and nums[j] such that |i - j| ≥ x. The constraint prevents comparing nearby elements, so the algorithm must track only values that are far enough apart in the array.

Approach 1: Brute Force with Constraint Check (O(n²) time, O(1) space)

The straightforward approach checks every valid pair. Iterate through the array using two nested loops and only evaluate pairs where |i - j| ≥ x. For each valid pair, compute abs(nums[i] - nums[j]) and track the minimum. This method is simple and clearly demonstrates the constraint logic, but it performs up to n² comparisons and becomes impractical for large inputs.

Approach 2: Sliding Window with Sorted List (O(n log n) time, O(n) space)

The optimized approach maintains a dynamically sorted structure of eligible elements. As you iterate through the array, add the element nums[i - x] into an ordered structure once it becomes valid for comparison. This ensures every stored value satisfies the index distance constraint.

Use an ordered set or sorted list and locate the closest values to nums[i] using binary search. Specifically, find the first element greater than or equal to nums[i] and also check the previous element. These two candidates produce the smallest possible absolute difference in a sorted structure. Update the global minimum after each comparison.

The key insight: in a sorted structure, the nearest values to a number must lie directly adjacent in order. Binary search finds those candidates in O(log n), and insertion also costs O(log n) for balanced trees (or O(n) in Python lists but still efficient in practice). Iterating once through the array results in overall O(n log n) time.

Recommended for interviews: Start with the brute force idea to show you understand the constraint and pair comparison logic. Then move to the ordered-set solution. Interviewers typically expect the O(n log n) approach using a balanced tree, TreeSet, or sorted container because it demonstrates knowledge of binary search on dynamic data structures.

Approach 1: Sliding Window with Sorted List

This approach uses a sliding window along with a sorted data structure to efficiently find the minimum absolute difference between elements that are at least 'x' indices apart. As we iterate over the array, we maintain a sorted list of the last 'x' elements. For each element 'nums[i]', we calculate the difference with the closest elements in the sorted list and update the minimum difference accordingly. This method is efficient due to the sorted nature of the data structure, which allows quick access to the closest elements.
from sortedcontainers import SortedList

def minAbsoluteDifference(nums, x):
    n = len(nums)
    sorted_list = SortedList()
    min_diff = float('inf')
    for i in range(n):
        if i >= x:
            sorted_list.add(nums[i-x])
        if sorted_list:
            idx = sorted_list.bisect_left(nums[i])
            if idx < len(sorted_list):
                min_diff = min(min_diff, abs(sorted_list[idx] - nums[i]))
            if idx > 0:
                min_diff = min(min_diff, abs(sorted_list[idx-1] - nums[i]))
    return min_diff
import java.util.*;

public class Solution {
    public int minAbsoluteDifference(int[] nums, int x) {
        TreeSet<Integer> sortedSet = new TreeSet<>();
        int minDiff = Integer.MAX_VALUE;
        for (int i = 0; i < nums.length; i++) {
            if (i >= x) {
                sortedSet.add(nums[i - x]);
            }
            if (!sortedSet.isEmpty()) {
                Integer higher = sortedSet.ceiling(nums[i]);
                Integer lower = sortedSet.floor(nums[i]);
                if (higher != null) {
                    minDiff = Math.min(minDiff, Math.abs(higher - nums[i]));
                }
                if (lower != null) {
                    minDiff = Math.min(minDiff, Math.abs(lower - nums[i]));
                }
            }
        }
        return minDiff;
    }
}
#include <set>
#include <vector>
#include <algorithm>
#include <cmath>

int minAbsoluteDifference(std::vector<int>& nums, int x) {
    std::multiset<int> sortedSet;
    int minDiff = INT_MAX;
    for (int i = 0; i < nums.size(); ++i) {
        if (i >= x) {
            sortedSet.insert(nums[i-x]);
        }
        if (!sortedSet.empty()) {
            auto it = sortedSet.lower_bound(nums[i]);
            if (it != sortedSet.end()) {
                minDiff = std::min(minDiff, std::abs(*it - nums[i]));
            }
            if (it != sortedSet.begin()) {
                --it;
                minDiff = std::min(minDiff, std::abs(*it - nums[i]));
            }
        }
    }
    return minDiff;
}
function minAbsoluteDifference(nums, x) {
    const sortedList = new Set();
    let minDiff = Infinity;
    function insertSorted(num) {
        sortedList.add(num);
        sortedList = new Set(Array.from(sortedList).sort((a, b) => a - b));
    }
    for (let i = 0; i < nums.length; i++) {
        if (i >= x) {
            insertSorted(nums[i - x]);
        }
        if (sortedList.size > 0) {
            const sortedArr = Array.from(sortedList);
            const idx = sortedArr.findIndex(v => v >= nums[i]);
            if (idx < sortedArr.length) {
                minDiff = Math.min(minDiff, Math.abs(sortedArr[idx] - nums[i]));
            }
            if (idx > 0) {
                minDiff = Math.min(minDiff, Math.abs(sortedArr[idx - 1] - nums[i]));
            }
        }
    }
    return minDiff;
}
using System;
using System.Collections.Generic;

public class Solution {
    public int MinAbsoluteDifference(int[] nums, int x) {
        SortedSet<int> sortedSet = new SortedSet<int>();
        int minDiff = int.MaxValue;
        for (int i = 0; i < nums.Length; i++) {
            if (i >= x) {
                sortedSet.Add(nums[i - x]);
            }
            if (sortedSet.Count > 0) {
                int? lower = sortedSet.GetViewBetween(int.MinValue, nums[i]).Max;
                int? higher = sortedSet.GetViewBetween(nums[i], int.MaxValue).Min;
                if (higher.HasValue) {
                    minDiff = Math.Min(minDiff, Math.Abs(higher.Value - nums[i]));
                }
                if (lower.HasValue) {
                    minDiff = Math.Min(minDiff, Math.Abs(lower.Value - nums[i]));
                }
            }
        }
        return minDiff;
    }
}

This solution uses the SortedList from the 'sortedcontainers' module for efficient insertion and access. As we iterate over elements in 'nums', we maintain a sliding window of the last 'x' elements in sorted order. For each element, we check adjacent elements from the sorted list to find the minimum difference and update our result.

Complexity

Time Complexity: O(n log x), where n is the length of the array and x is the constraint for indices apart. Space Complexity: O(x) due to storing the elements in the sorted list.

Try this approach in the editor

Approach 2: Brute Force with Constraint Check

A straightforward solution is to iterate through each pair of elements in 'nums' and compute their absolute difference if they meet the constraint |i - j| >= x. While this approach is simple and easy to implement, it is not optimal for large inputs as it runs in quadratic time. Despite its inefficiency, it can serve as a verification method for small inputs or in scenarios where performance constraints are relaxed.
def minAbsoluteDifference(nums, x):
    min_diff = float('inf')
    n = len(nums)
    for i in range(n):
        for j in range(i + x, n):
            min_diff = min(min_diff, abs(nums[i] - nums[j]))
    return min_diff
public class Solution {
    public int minAbsoluteDifference(int[] nums, int x) {
        int minDiff = Integer.MAX_VALUE;
        for (int i = 0; i < nums.length; i++) {
            for (int j = i + x; j < nums.length; j++) {
                minDiff = Math.min(minDiff, Math.abs(nums[i] - nums[j]));
            }
        }
        return minDiff;
    }
}
#include <vector>
#include <algorithm>
#include <cstdlib>

int minAbsoluteDifference(std::vector<int>& nums, int x) {
    int minDiff = INT_MAX;
    for (int i = 0; i < nums.size(); ++i) {
        for (int j = i + x; j < nums.size(); ++j) {
            minDiff = std::min(minDiff, std::abs(nums[i] - nums[j]));
        }
    }
    return minDiff;
}
function minAbsoluteDifference(nums, x) {
    let minDiff = Infinity;
    for (let i = 0; i < nums.length; i++) {
        for (let j = i + x; j < nums.length; j++) {
            minDiff = Math.min(minDiff, Math.abs(nums[i] - nums[j]));
        }
    }
    return minDiff;
}
public class Solution {
    public int MinAbsoluteDifference(int[] nums, int x) {
        int minDiff = int.MaxValue;
        for (int i = 0; i < nums.Length; i++) {
            for (int j = i + x; j < nums.Length; j++) {
                minDiff = Math.Min(minDiff, Math.Abs(nums[i] - nums[j]));
            }
        }
        return minDiff;
    }
}

This Python code loops through each permissible pair, checks if their index difference meets the constraint and calculates the absolute difference to find the minimum.

Complexity

Time Complexity: O(n^2), as all pairs are checked. Space Complexity: O(1), as only simple variables are used.

Try this approach in the editor

Approach 3: Ordered Set

We create an ordered set to store the elements whose distance to the current index is at least x.

Next, we enumerate from index i = x, each time we add nums[i - x] into the ordered set. Then we find the two elements in the ordered set which are closest to nums[i], and the minimum absolute difference between them is the answer.

The time complexity is O(n times log n), and the space complexity is O(n). Where n is the length of array nums.

function minAbsoluteDifference(nums: number[], x: number): number {
    const s = new TreeMultiSet<number>();
    const inf = 1 << 30;
    let ans = inf;
    for (let i = x; i < nums.length; ++i) {
        s.add(nums[i - x]);
        const c = s.ceil(nums[i]);
        const f = s.floor(nums[i]);
        if (c) {
            ans = Math.min(ans, c - nums[i]);
        }
        if (f) {
            ans = Math.min(ans, nums[i] - f);
        }
    }
    return ans;
}

type Compare<T> = (lhs: T, rhs: T) => number;

class RBTreeNode<T = number> {
    data: T;
    count: number;
    left: RBTreeNode<T> | null;
    right: RBTreeNode<T> | null;
    parent: RBTreeNode<T> | null;
    color: number;
    constructor(data: T) {
        this.data = data;
        this.left = this.right = this.parent = null;
        this.color = 0;
        this.count = 1;
    }

    sibling(): RBTreeNode<T> | null {
        if (!this.parent) return null; // sibling null if no parent
        return this.isOnLeft() ? this.parent.right : this.parent.left;
    }

    isOnLeft(): boolean {
        return this === this.parent!.left;
    }

    hasRedChild(): boolean {
        return (
            Boolean(this.left && this.left.color === 0) ||
            Boolean(this.right && this.right.color === 0)
        );
    }
}

class RBTree<T> {
    root: RBTreeNode<T> | null;
    lt: (l: T, r: T) => boolean;
    constructor(compare: Compare<T> = (l: T, r: T) => (l < r ? -1 : l > r ? 1 : 0)) {
        this.root = null;
        this.lt = (l: T, r: T) => compare(l, r) < 0;
    }

    rotateLeft(pt: RBTreeNode<T>): void {
        const right = pt.right!;
        pt.right = right.left;

        if (pt.right) pt.right.parent = pt;
        right.parent = pt.parent;

        if (!pt.parent) this.root = right;
        else if (pt === pt.parent.left) pt.parent.left = right;
        else pt.parent.right = right;

        right.left = pt;
        pt.parent = right;
    }

    rotateRight(pt: RBTreeNode<T>): void {
        const left = pt.left!;
        pt.left = left.right;

        if (pt.left) pt.left.parent = pt;
        left.parent = pt.parent;

        if (!pt.parent) this.root = left;
        else if (pt === pt.parent.left) pt.parent.left = left;
        else pt.parent.right = left;

        left.right = pt;
        pt.parent = left;
    }

    swapColor(p1: RBTreeNode<T>, p2: RBTreeNode<T>): void {
        const tmp = p1.color;
        p1.color = p2.color;
        p2.color = tmp;
    }

    swapData(p1: RBTreeNode<T>, p2: RBTreeNode<T>): void {
        const tmp = p1.data;
        p1.data = p2.data;
        p2.data = tmp;
    }

    fixAfterInsert(pt: RBTreeNode<T>): void {
        let parent = null;
        let grandParent = null;

        while (pt !== this.root && pt.color !== 1 && pt.parent?.color === 0) {
            parent = pt.parent;
            grandParent = pt.parent.parent;

            /*  Case : A
                Parent of pt is left child of Grand-parent of pt */
            if (parent === grandParent?.left) {
                const uncle = grandParent.right;

                /* Case : 1
                   The uncle of pt is also red
                   Only Recoloring required */
                if (uncle && uncle.color === 0) {
                    grandParent.color = 0;
                    parent.color = 1;
                    uncle.color = 1;
                    pt = grandParent;
                } else {
                    /* Case : 2
                       pt is right child of its parent
                       Left-rotation required */
                    if (pt === parent.right) {
                        this.rotateLeft(parent);
                        pt = parent;
                        parent = pt.parent;
                    }

                    /* Case : 3
                       pt is left child of its parent
                       Right-rotation required */
                    this.rotateRight(grandParent);
                    this.swapColor(parent!, grandParent);
                    pt = parent!;
                }
            } else {
                /* Case : B
               Parent of pt is right child of Grand-parent of pt */
                const uncle = grandParent!.left;

                /*  Case : 1
                    The uncle of pt is also red
                    Only Recoloring required */
                if (uncle != null && uncle.color === 0) {
                    grandParent!.color = 0;
                    parent.color = 1;
                    uncle.color = 1;
                    pt = grandParent!;
                } else {
                    /* Case : 2
                       pt is left child of its parent
                       Right-rotation required */
                    if (pt === parent.left) {
                        this.rotateRight(parent);
                        pt = parent;
                        parent = pt.parent;
                    }

                    /* Case : 3
                       pt is right child of its parent
                       Left-rotation required */
                    this.rotateLeft(grandParent!);
                    this.swapColor(parent!, grandParent!);
                    pt = parent!;
                }
            }
        }
        this.root!.color = 1;
    }

    delete(val: T): boolean {
        const node = this.find(val);
        if (!node) return false;
        node.count--;
        if (!node.count) this.deleteNode(node);
        return true;
    }

    deleteAll(val: T): boolean {
        const node = this.find(val);
        if (!node) return false;
        this.deleteNode(node);
        return true;
    }

    deleteNode(v: RBTreeNode<T>): void {
        const u = BSTreplace(v);

        // True when u and v are both black
        const uvBlack = (u === null || u.color === 1) && v.color === 1;
        const parent = v.parent!;

        if (!u) {
            // u is null therefore v is leaf
            if (v === this.root) this.root = null;
            // v is root, making root null
            else {
                if (uvBlack) {
                    // u and v both black
                    // v is leaf, fix double black at v
                    this.fixDoubleBlack(v);
                } else {
                    // u or v is red
                    if (v.sibling()) {
                        // sibling is not null, make it red"
                        v.sibling()!.color = 0;
                    }
                }
                // delete v from the tree
                if (v.isOnLeft()) parent.left = null;
                else parent.right = null;
            }
            return;
        }

        if (!v.left || !v.right) {
            // v has 1 child
            if (v === this.root) {
                // v is root, assign the value of u to v, and delete u
                v.data = u.data;
                v.left = v.right = null;
            } else {
                // Detach v from tree and move u up
                if (v.isOnLeft()) parent.left = u;
                else parent.right = u;
                u.parent = parent;
                if (uvBlack) this.fixDoubleBlack(u);
                // u and v both black, fix double black at u
                else u.color = 1; // u or v red, color u black
            }
            return;
        }

        // v has 2 children, swap data with successor and recurse
        this.swapData(u, v);
        this.deleteNode(u);

        // find node that replaces a deleted node in BST
        function BSTreplace(x: RBTreeNode<T>): RBTreeNode<T> | null {
            // when node have 2 children
            if (x.left && x.right) return successor(x.right);
            // when leaf
            if (!x.left && !x.right) return null;
            // when single child
            return x.left ?? x.right;
        }
        // find node that do not have a left child
        // in the subtree of the given node
        function successor(x: RBTreeNode<T>): RBTreeNode<T> {
            let temp = x;
            while (temp.left) temp = temp.left;
            return temp;
        }
    }

    fixDoubleBlack(x: RBTreeNode<T>): void {
        if (x === this.root) return; // Reached root

        const sibling = x.sibling();
        const parent = x.parent!;
        if (!sibling) {
            // No sibiling, double black pushed up
            this.fixDoubleBlack(parent);
        } else {
            if (sibling.color === 0) {
                // Sibling red
                parent.color = 0;
                sibling.color = 1;
                if (sibling.isOnLeft()) this.rotateRight(parent);
                // left case
                else this.rotateLeft(parent); // right case
                this.fixDoubleBlack(x);
            } else {
                // Sibling black
                if (sibling.hasRedChild()) {
                    // at least 1 red children
                    if (sibling.left && sibling.left.color === 0) {
                        if (sibling.isOnLeft()) {
                            // left left
                            sibling.left.color = sibling.color;
                            sibling.color = parent.color;
                            this.rotateRight(parent);
                        } else {
                            // right left
                            sibling.left.color = parent.color;
                            this.rotateRight(sibling);
                            this.rotateLeft(parent);
                        }
                    } else {
                        if (sibling.isOnLeft()) {
                            // left right
                            sibling.right!.color = parent.color;
                            this.rotateLeft(sibling);
                            this.rotateRight(parent);
                        } else {
                            // right right
                            sibling.right!.color = sibling.color;
                            sibling.color = parent.color;
                            this.rotateLeft(parent);
                        }
                    }
                    parent.color = 1;
                } else {
                    // 2 black children
                    sibling.color = 0;
                    if (parent.color === 1) this.fixDoubleBlack(parent);
                    else parent.color = 1;
                }
            }
        }
    }

    insert(data: T): boolean {
        // search for a position to insert
        let parent = this.root;
        while (parent) {
            if (this.lt(data, parent.data)) {
                if (!parent.left) break;
                else parent = parent.left;
            } else if (this.lt(parent.data, data)) {
                if (!parent.right) break;
                else parent = parent.right;
            } else break;
        }

        // insert node into parent
        const node = new RBTreeNode(data);
        if (!parent) this.root = node;
        else if (this.lt(node.data, parent.data)) parent.left = node;
        else if (this.lt(parent.data, node.data)) parent.right = node;
        else {
            parent.count++;
            return false;
        }
        node.parent = parent;
        this.fixAfterInsert(node);
        return true;
    }

    find(data: T): RBTreeNode<T> | null {
        let p = this.root;
        while (p) {
            if (this.lt(data, p.data)) {
                p = p.left;
            } else if (this.lt(p.data, data)) {
                p = p.right;
            } else break;
        }
        return p ?? null;
    }

    *inOrder(root: RBTreeNode<T> = this.root!): Generator<T, undefined, void> {
        if (!root) return;
        for (const v of this.inOrder(root.left!)) yield v;
        yield root.data;
        for (const v of this.inOrder(root.right!)) yield v;
    }

    *reverseInOrder(root: RBTreeNode<T> = this.root!): Generator<T, undefined, void> {
        if (!root) return;
        for (const v of this.reverseInOrder(root.right!)) yield v;
        yield root.data;
        for (const v of this.reverseInOrder(root.left!)) yield v;
    }
}

class TreeMultiSet<T = number> {
    _size: number;
    tree: RBTree<T>;
    compare: Compare<T>;
    constructor(
        collection: T[] | Compare<T> = [],
        compare: Compare<T> = (l: T, r: T) => (l < r ? -1 : l > r ? 1 : 0),
    ) {
        if (typeof collection === 'function') {
            compare = collection;
            collection = [];
        }
        this._size = 0;
        this.compare = compare;
        this.tree = new RBTree(compare);
        for (const val of collection) this.add(val);
    }

    size(): number {
        return this._size;
    }

    has(val: T): boolean {
        return !!this.tree.find(val);
    }

    add(val: T): boolean {
        const successful = this.tree.insert(val);
        this._size++;
        return successful;
    }

    delete(val: T): boolean {
        const successful = this.tree.delete(val);
        if (!successful) return false;
        this._size--;
        return true;
    }

    count(val: T): number {
        const node = this.tree.find(val);
        return node ? node.count : 0;
    }

    ceil(val: T): T | undefined {
        let p = this.tree.root;
        let higher = null;
        while (p) {
            if (this.compare(p.data, val) >= 0) {
                higher = p;
                p = p.left;
            } else {
                p = p.right;
            }
        }
        return higher?.data;
    }

    floor(val: T): T | undefined {
        let p = this.tree.root;
        let lower = null;
        while (p) {
            if (this.compare(val, p.data) >= 0) {
                lower = p;
                p = p.right;
            } else {
                p = p.left;
            }
        }
        return lower?.data;
    }

    higher(val: T): T | undefined {
        let p = this.tree.root;
        let higher = null;
        while (p) {
            if (this.compare(val, p.data) < 0) {
                higher = p;
                p = p.left;
            } else {
                p = p.right;
            }
        }
        return higher?.data;
    }

    lower(val: T): T | undefined {
        let p = this.tree.root;
        let lower = null;
        while (p) {
            if (this.compare(p.data, val) < 0) {
                lower = p;
                p = p.right;
            } else {
                p = p.left;
            }
        }
        return lower?.data;
    }

    first(): T | undefined {
        return this.tree.inOrder().next().value;
    }

    last(): T | undefined {
        return this.tree.reverseInOrder().next().value;
    }

    shift(): T | undefined {
        const first = this.first();
        if (first === undefined) return undefined;
        this.delete(first);
        return first;
    }

    pop(): T | undefined {
        const last = this.last();
        if (last === undefined) return undefined;
        this.delete(last);
        return last;
    }

    *[Symbol.iterator](): Generator<T, void, void> {
        yield* this.values();
    }

    *keys(): Generator<T, void, void> {
        for (const val of this.values()) yield val;
    }

    *values(): Generator<T, undefined, void> {
        for (const val of this.tree.inOrder()) {
            let count = this.count(val);
            while (count--) yield val;
        }
        return undefined;
    }

    /**
     * Return a generator for reverse order traversing the multi-set
     */
    *rvalues(): Generator<T, undefined, void> {
        for (const val of this.tree.reverseInOrder()) {
            let count = this.count(val);
            while (count--) yield val;
        }
        return undefined;
    }
}
func minAbsoluteDifference(nums []int, x int) int {
	rbt := redblacktree.NewWithIntComparator()
	ans := 1 << 30
	for i := x; i < len(nums); i++ {
		rbt.Put(nums[i-x], nil)
		c, _ := rbt.Ceiling(nums[i])
		f, _ := rbt.Floor(nums[i])
		if c != nil {
			ans = min(ans, c.Key.(int)-nums[i])
		}
		if f != nil {
			ans = min(ans, nums[i]-f.Key.(int))
		}
	}
	return ans
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Sliding Window with Sorted List

Time Complexity: O(n log x), where n is the length of the array and x is the constraint for indices apart. Space Complexity: O(x) due to storing the elements in the sorted list.

Brute Force with Constraint Check

Time Complexity: O(n^2), as all pairs are checked. Space Complexity: O(1), as only simple variables are used.

Ordered Set–

Complexity analysis

ApproachTimeSpaceWhen to Use
Brute Force with Constraint CheckO(n²)O(1)Good for understanding the constraint logic or very small arrays
Sliding Window with Sorted List / Ordered SetO(n log n)O(n)Best general solution; efficient for large inputs and typical interview expectations

Frequently asked questions

Is Minimum Absolute Difference Between Elements With Constraint easy or hard?

The problem is rated Medium on LeetCode because the brute force idea is simple but inefficient. The challenge is recognizing that a dynamically maintained sorted structure enables fast nearest-value queries while respecting the index distance constraint.

Minimum Absolute Difference Between Elements With Constraint Python/Java solution

In Python, a sorted list with the bisect module can maintain ordered elements and perform binary search for neighbors. In Java, TreeSet provides built-in methods like ceiling() and floor() to quickly locate the closest values. Both implementations run in O(n log n) time.

How to solve Minimum Absolute Difference Between Elements With Constraint in O(n)?

A strict O(n) solution is generally not feasible because you must maintain ordering to find the closest numeric value efficiently. Most optimal implementations rely on a balanced tree, TreeSet, or sorted container with binary search, resulting in O(n log n) time.

What is the best approach for Minimum Absolute Difference Between Elements With Constraint?

The most efficient approach uses a sliding window with an ordered set or sorted list. While iterating through the array, insert elements that are at least x indices behind the current index. Use binary search to find the closest values to the current number in O(log n). This produces an overall time complexity of O(n log n) with O(n) space.

Is Minimum Absolute Difference Between Elements With Constraint asked at Google/Amazon/Meta?

Problems combining ordered sets, binary search, and sliding window techniques commonly appear in interviews at companies like Google, Amazon, and Meta. This question tests the ability to maintain a dynamically sorted structure while enforcing index constraints.

What data structure is used in Minimum Absolute Difference Between Elements With Constraint?

The optimal solution uses an ordered set or balanced binary search tree. Examples include TreeSet in Java, multiset in C++, or a sorted list with bisect in Python. These structures allow efficient insertion and nearest-value lookup using binary search.

What is the time complexity of Minimum Absolute Difference Between Elements With Constraint?

The brute force method runs in O(n²) time because it compares all valid pairs that satisfy the index constraint. The optimized ordered-set approach reduces the complexity to O(n log n) by maintaining a sorted structure and using binary search to find the closest values efficiently.

Comments

Now write it yourselfClose this page and solve Minimum Absolute Difference Between Elements With Constraint in the editor, without looking.
Practise Minimum Absolute Difference Between Elements With Constraint