Start learning free

LESSON 194 OF 344 · NESTED LOOPS & BRUTE FORCE

Minimum Absolute Difference in Python: Brute Force with Nested Loops

Practice O(n2) 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

    PYTHON · NESTED LOOPS & BRUTE FORCE

    Minimum Absolute Difference in Python, explained

    Problem overview

    The method minimumAbsDifference receives a list nums of distinct integers. Among all pairs of elements, find the smallest absolute difference. Then return every pair whose difference equals that minimum. Each pair is written [a, b] with a < b, and the list of pairs is in ascending order.

    For nums = [4, 2, 1, 3], the smallest gap between any two numbers is 1. The pairs with that gap are 1 and 2, 2 and 3, 3 and 4, so the answer is [[1, 2], [2, 3], [3, 4]]. For [1, 3, 6, 10, 15] only 1 and 3 are 2 apart, and no other pair is that close, so the answer is [[1, 3]].

    Approach: look at every pair

    This chapter is about nested loops, so the lesson takes the direct route. Compare every element with every element after it, track the smallest difference seen so far, and keep the pairs that reach it.

    Keeping the pairs needs one rule. When a pair has a smaller difference than the current record, everything collected so far is out of date, so the list is replaced by a new list holding just that pair. When a pair ties with the record, it is added to the list.

    The cost is quadratic: a list of n numbers has about n * (n - 1) / 2 pairs. That is fine for small inputs. A later lesson on the same problem sorts the list first, so the closest pairs are neighbours, and checks only n - 1 pairs.

    Step by step

    1. Start the record with the first pair. minDiff begins as abs(nums[0] - nums[1]). A real difference as a starting value avoids a special "nothing yet" value. minDiffPairs starts as an empty list.
    2. Loop over the first element of each pair with i.
    3. Loop over the second element with j, starting at i + 1. Starting there means each pair is visited once, and an element is never paired with itself.
    4. Compute curDiff as abs(nums[i] - nums[j]). The input isn't sorted, so either element can be the larger, and abs removes the sign.
    5. If curDiff < minDiff, a new record has been found.
    6. Replace the record and the list. Set minDiff to curDiff, and set minDiffPairs to a new list with one pair. The pair is written smaller value first using min and max, because nums[i] may be the larger one.
    7. Otherwise, if curDiff == minDiff, the pair ties with the record.
    8. Add the tied pair to minDiffPairs, again as [min, max].
    9. Return sorted(minDiffPairs). Pairs are found in the order the loops visit them, which isn't the required ascending order.

    The solution in Python

    class Solution:
        def minimumAbsDifference(self, nums: List[int]) -> List[List[int]]:
            minDiff = abs(nums[0] - nums[1])
            minDiffPairs = []
            for i in range(0, len(nums)):
                for j in range(i + 1, len(nums)):
                    curDiff = abs(nums[i] - nums[j])
                    if curDiff < minDiff:
                        minDiff = curDiff
                        minDiffPairs = [[min(nums[i], nums[j]), max(nums[i], nums[j])]]
                    elif curDiff == minDiff:
                        minDiffPairs.append([min(nums[i], nums[j]), max(nums[i], nums[j])])
            return sorted(minDiffPairs)
    

    Python details worth a look:

    • Replacing, not clearing. The new-record branch assigns a fresh list instead of changing the old one. The old list is simply dropped.
    • Sorting lists of lists. Python compares two lists element by element, so sorted orders the pairs by the first number and uses the second to break ties. For example, sorted([[3, 4], [1, 2], [1, 0]]) gives [[1, 0], [1, 2], [3, 4]].
    • sorted returns a new list. It doesn't change minDiffPairs, which is why its result is returned directly. list.sort() would sort in place and return None.
    • range(i + 1, len(nums)) is empty when i is the last index, so the inner loop does nothing on the final pass of the outer one.

    Complexity

    Time: O(n²). The two loops visit about n * (n - 1) / 2 pairs, and each visit does constant work. Sorting the answer adds O(m log m) for m result pairs, and m is smaller than n because distinct numbers can give at most n - 1 closest pairs. This is only practical for small lists. With the upper limit of 100,000 numbers in the statement, the pair count would be around five billion, which is why the sorting approach exists.

    Space: O(m) for the list of pairs, where m is the number of closest pairs. Nothing else grows with the input.

    Edge cases and common mistakes

    • Two elements. [5, 1] returns [[1, 5]]. The inner loop runs once, and the pair is written smaller first.
    • Negative numbers. The difference is taken with abs, so [-14, -10] has gap 4. The pair is written [-14, -10], since -14 is smaller.
    • Several ties. In [4, 2, 1, 3] the first pair visited is 4 and 2 with gap 2. Later pairs with gap 1 replace it, then tie with each other and are appended. The order of discovery differs from the final order, so the last sorted is needed.
    • Forgetting to reset the list. If a smaller gap is found and the old pairs aren't discarded, the result includes pairs that aren't the closest.
    • Skipping min and max. Writing [nums[i], nums[j]] gives pairs like [4, 2] when the earlier element is larger.
    • Starting j at i. That pairs each element with itself, a gap of 0, which would then win every time.

    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, 1] gives [[1, 5]].
    Keep going with PythonAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free