Start learning free

LESSON 202 OF 344 · SORTING

Minimum Absolute Difference in Java: O(n log n) by Sorting

Practice O(n log n) Read the full explanation

Given an array of distinct integers nums, find all pairs of elements with the minimum absolute difference of any two elements.

Return a list of pairs in ascending order(with respect to pairs), each pair [a, b] follows

  • a, b are from nums
  • a < b
  • b - a equals to the minimum absolute difference of any two elements in nums

Example 1:

Input: nums = [4,2,1,3]
Output: [[1,2],[2,3],[3,4]]
Explanation: The minimum absolute difference is 1. List all pairs with difference equal to 1 in ascending order.

Example 2:

Input: nums = [1,3,6,10,15]
Output: [[1,3]]

Example 3:

Input: nums = [3,8,-10,23,19,-4,-14,27]
Output: [[-14,-10],[19,23],[23,27]]

Constraints:

  • 2 <= nums.length <= 105
  • -106 <= nums[i] <= 106

STEP 1 OF 9
    Ctrl + Enter to check

    JAVA · SORTING

    Minimum Absolute Difference in Java, explained

    Problem overview

    The method minimumAbsDifference receives an array nums of distinct integers. It must find the smallest absolute difference between any two elements and return every pair [a, b] with a < b whose difference b - a equals that smallest value. The pairs come back in ascending order.

    For nums = [4, 2, 1, 3] the smallest difference is 1, and the pairs are [[1, 2], [2, 3], [3, 4]]. For [1, 3, 6, 10, 15] the answer is [[1, 3]].

    Approach: sort, then compare neighbours

    The brute-force way checks every pair of elements, which is O(n²). With up to 100,000 elements, that is far too slow. Sorting removes the need for it.

    In a sorted array, take any two elements that are not neighbours, say at positions p and q with something between them. The element in between lies within that range, so it forms a pair with each of them that has a strictly smaller gap. A pair that is not adjacent therefore can never have the minimum difference. Only neighbouring elements need to be compared, which takes one pass.

    Sorting also solves the output order. The adjacent pairs, read left to right, already come out as ascending [a, b] with a < b, so no extra sort of the result is needed.

    On [4, 2, 1, 3], sorting gives [1, 2, 3, 4]. The neighbour gaps are 1, 1 and 1, all equal to the minimum, so all three pairs are returned.

    A longer trace shows the reset. Take [3, 8, -10, 23, 19, -4, -14, 27], which sorts to [-14, -10, -4, 3, 8, 19, 23, 27]. The neighbour gaps are 4, 6, 7, 5, 11, 4 and 4. The loop starts with minDiff = 4, and the first pair [-14, -10] is added as a tie. The gaps 6, 7, 5 and 11 are all larger and are ignored. The last two gaps equal 4, so [19, 23] and [23, 27] are appended. No gap was smaller than 4, so the list was never reset.

    The first lesson on this problem solves it with two nested loops. The idea there is the same, keep the best gap and reset on a new record, but it examines every pair and has to sort the result at the end. Sorting the input first turns n²/2 comparisons into n - 1.

    Step by step

    1. Sort the array in place with Arrays.sort(nums).
    2. Start the best gap at the first adjacent difference, nums[1] - nums[0], and create an empty List<List<Integer>> named minDiffPairs. In a sorted array the later number is never smaller, so no Math.abs is needed.
    3. Loop over the neighbours with i starting at 1, so each step looks at the pair nums[i - 1] and nums[i].
    4. Compute the gap as curDiff, equal to nums[i] - nums[i - 1].
    5. Test for a new record with curDiff < minDiff.
    6. On a record, reset. Update minDiff, replace the list with a new empty one, and add the pair Arrays.asList(nums[i - 1], nums[i]). Every pair collected so far had a larger gap, so it no longer qualifies.
    7. Test for a tie with an else if on curDiff == minDiff.
    8. On a tie, append the same kind of pair.
    9. Return minDiffPairs after the loop.

    The solution in Java

    class Solution {
        public List<List<Integer>> minimumAbsDifference(int[] nums) {
            Arrays.sort(nums);
            int minDiff = nums[1] - nums[0];
            List<List<Integer>> minDiffPairs = new ArrayList<>();
            for (int i = 1; i < nums.length; i++) {
                int curDiff = nums[i] - nums[i - 1];
                if (curDiff < minDiff) {
                    minDiff = curDiff;
                    minDiffPairs = new ArrayList<>();
                    minDiffPairs.add(Arrays.asList(nums[i - 1], nums[i]));
                } else if (curDiff == minDiff) {
                    minDiffPairs.add(Arrays.asList(nums[i - 1], nums[i]));
                }
            }
            return minDiffPairs;
        }
    }
    

    The Java details worth a closer look:

    • The first pair is added by the loop. minDiff starts as the first gap while the list starts empty. At i = 1 the gap equals minDiff, so the tie branch adds the first pair.
    • Arrays.sort changes the caller's array. It sorts the int[] in place. Sort a copy if the original order must survive.
    • Arrays.asList(nums[i - 1], nums[i]) boxes the two int values into Integer objects and returns a fixed-size List<Integer>, which fits in minDiffPairs. You can read it but not add to it or remove from it.
    • The subtraction can't overflow here. The values lie between -1,000,000 and 1,000,000, so a gap is at most 2,000,000. For arbitrary int values, nums[i] - nums[i - 1] could exceed the int range, and the arithmetic would need long.

    Complexity

    Time: O(n log n). Sorting costs O(n log n) and the pass over neighbours costs O(n). This beats the O(n²) of checking every pair.

    Space: O(1) beyond the output, apart from the sort's own working memory. The result list can hold up to n - 1 pairs, as in an evenly spaced array.

    Edge cases and common mistakes

    • Two elements. [5, 2] sorts to [2, 5] and returns [[2, 5]].
    • All gaps equal. [1, 4, 7, 10] returns all three neighbour pairs.
    • Negative numbers. [-5, -1, 3, 7] returns [[-5, -1], [-1, 3], [3, 7]]. Sorting handles negatives naturally.
    • Forgetting to reset the list. If a new record only appends, pairs with larger gaps stay in the result.
    • Dropping the tie branch. The method would return one pair, not all of the tied ones.
    • Forgetting to sort. Comparing neighbours in the original order finds nothing useful.
    • A one-element array. nums[1] would throw, but the statement guarantees at least two elements.

    Testing

    • [4, 2, 1, 3] gives [[1, 2], [2, 3], [3, 4]].
    • [1, 3, 6, 10, 15] gives [[1, 3]].
    • [3, 8, -10, 23, 19, -4, -14, 27] gives [[-14, -10], [19, 23], [23, 27]].
    • [5, 2] gives [[2, 5]].
    • [-5, -1, 3, 7] gives [[-5, -1], [-1, 3], [3, 7]].
    Keep going with JavaAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free