LeetCode 3667 - Sort Array By Absolute Value
The problem asks us to reorder an integer array such that the elements are sorted in non-decreasing order of their absolute values.
Difficulty: 🟢 Easy
Topics: Array, Math, Two Pointers, Sorting
Solution
Problem Understanding
The problem asks us to reorder an integer array such that the elements are sorted in non-decreasing order of their absolute values. This means we are not sorting based on the actual numeric value, but rather based on how far each number is from zero on the number line, regardless of sign.
In simpler terms, we compute abs(nums[i]) for every element, and then arrange the original numbers so that these absolute values appear in sorted order. Importantly, when two numbers have the same absolute value, either order is acceptable, since the problem allows returning any valid rearrangement.
The input is a list of integers nums, with constraints ensuring a small input size: at most 100 elements, and values ranging between -100 and 100. This indicates that both simple sorting and even less efficient approaches would pass easily, but we should still aim for a clean optimal solution.
Edge cases include arrays with all positive numbers, all negative numbers, mixtures of equal absolute values like [1, -1], single-element arrays, and arrays already sorted by absolute value.
The key challenge is recognizing that we are not sorting by value but by a derived key, absolute value, which directly suggests a custom sort.
Approaches
The brute-force approach is to repeatedly select the element with the smallest absolute value from the remaining unsorted portion and append it to the result array. This behaves like a selection sort variant where comparison is based on abs(x). While correct, this requires scanning the remaining elements repeatedly, leading to quadratic time complexity.
The optimal approach leverages the built-in sorting mechanism with a custom key function. Since sorting algorithms in modern languages are highly optimized (typically Timsort), we simply sort the array using abs(x) as the key. This reduces the problem to a single pass sort operation.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n²) | O(n) | Repeatedly select minimum absolute value |
| Optimal | O(n log n) | O(1) to O(n) | Sort using absolute value as key |
Algorithm Walkthrough
The optimal algorithm is straightforward due to the presence of a natural ordering key.
- Define a comparison key based on absolute value, meaning each element
xis compared usingabs(x)instead ofx. This ensures that sorting is guided by distance from zero rather than signed magnitude. - Apply a sorting algorithm to the entire array using this key. The sorting algorithm internally compares elements by their absolute values and rearranges them accordingly.
- Since the problem allows any valid ordering when absolute values are equal, we do not need a secondary tie-break rule. The default stability of the sort implementation is sufficient.
- Return the sorted array directly as it now satisfies the non-decreasing absolute value property.
Why it works
The correctness comes from the fact that sorting by a monotonic transformation key, in this case f(x) = abs(x), preserves a valid total ordering over all elements with respect to the required criterion. Every element is placed such that no later element has a smaller absolute value than an earlier one, which exactly matches the problem requirement.
Python Solution
from typing import List
class Solution:
def sortByAbsoluteValue(self, nums: List[int]) -> List[int]:
return sorted(nums, key=abs)
The implementation uses Python’s built-in sorted function with key=abs, which ensures each element is compared using its absolute value rather than its raw integer value. The function returns a new sorted list, leaving the original input unchanged.
Go Solution
import "sort"
func sortByAbsoluteValue(nums []int) []int {
sort.Slice(nums, func(i, j int) bool {
return abs(nums[i]) < abs(nums[j])
})
return nums
}
func abs(x int) int {
if x < 0 {
return -x
}
return x
}
In Go, we use sort.Slice with a custom comparator function that compares absolute values. Unlike Python, Go requires explicitly defining the absolute value function. The sorting is done in-place on the slice, which is idiomatic in Go and avoids additional memory allocation.
Worked Examples
Example 1: nums = [3, -1, -4, 1, 5]
We compute absolute values and sort based on them.
| Step | Array State | Absolute Values |
|---|---|---|
| Initial | [3, -1, -4, 1, 5] | [3, 1, 4, 1, 5] |
| After sorting | [-1, 1, 3, -4, 5] | [1, 1, 3, 4, 5] |
The result is valid because elements are ordered by increasing absolute value.
Example 2: nums = [-100, 100]
| Step | Array State | Absolute Values |
|---|---|---|
| Initial | [-100, 100] | [100, 100] |
| After sorting | [-100, 100] | [100, 100] |
Both outputs are valid since the absolute values are equal, so any order is acceptable.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n log n) | Sorting dominates, comparing elements by absolute value |
| Space | O(1) to O(n) | Depends on sorting implementation (Python uses Timsort auxiliary space in worst case) |
The complexity is determined entirely by the sorting operation, as computing absolute values is O(1) per element and done during comparisons.
Test Cases
assert Solution().sortByAbsoluteValue([3,-1,-4,1,5]) in [[-1,1,3,-4,5],[1,-1,3,-4,5]] # example case
assert Solution().sortByAbsoluteValue([-100,100]) in [[-100,100],[100,-100]] # equal abs values
assert Solution().sortByAbsoluteValue([0]) == [0] # single element
assert Solution().sortByAbsoluteValue([2, -2, 1, -1])[:2] in ([1,-1], [-1,1]) # ties in abs
assert Solution().sortByAbsoluteValue([5,4,3,2,1]) == [1,2,3,4,5] # all positive
assert Solution().sortByAbsoluteValue([-5,-4,-3,-2,-1]) == [-1,-2,-3,-4,-5] # all negative
| Test | Why |
|---|---|
| mixed positives and negatives | validates general ordering |
| equal absolute values | checks tie handling |
| single element | minimal boundary |
| alternating signs | stress symmetry handling |
| already sorted positives | confirms no disruption |
| all negatives | ensures abs-based ordering |
Edge Cases
A single-element array is an important edge case because the sorting operation should return the same array unchanged. This can expose incorrect implementations that assume at least two elements exist.
Arrays where all elements have identical absolute values, such as [3, -3, 3, -3], are also critical. Since all comparison keys are equal, any permutation is valid, and the implementation must not rely on unstable assumptions.
Another edge case involves already sorted or reverse-sorted inputs by absolute value. These test whether the sorting logic incorrectly disturbs already valid orderings or whether it correctly preserves a valid sorted result.
Finally, arrays containing zero should be considered carefully. Zero has absolute value zero and must always appear at the beginning of the result, and implementations must ensure it is not mishandled by custom absolute value logic or comparator errors.