LeetCode 2161 - Partition Array According to Given Pivot
This problem asks us to rearrange an array around a given pivot value while preserving relative ordering inside certain groups. We are given an integer array nums and an integer pivot. The goal is to reorganize the array into three consecutive sections: 1.
Difficulty: 🟡 Medium
Topics: Array, Two Pointers, Simulation
Solution
Problem Understanding
This problem asks us to rearrange an array around a given pivot value while preserving relative ordering inside certain groups.
We are given an integer array nums and an integer pivot. The goal is to reorganize the array into three consecutive sections:
- All elements smaller than
pivot - All elements equal to
pivot - All elements greater than
pivot
The important detail is that the rearrangement must be stable for the elements less than the pivot and for the elements greater than the pivot. Stability means that if two elements originally appeared in a certain order, they must remain in that same order after rearrangement.
For example, if the elements smaller than the pivot appear in the original array as:
9, 5, 3
then they must appear in exactly that order in the final answer. We cannot reorder them into something like:
3, 5, 9
The same rule applies to elements greater than the pivot.
The constraints tell us several important things:
- The array length can be as large as
10^5 - Values may be negative
- The pivot is guaranteed to exist in the array
Since the array can be very large, an inefficient quadratic solution would be too slow. We need a linear or near-linear solution.
There are several edge cases worth thinking about early:
- Arrays where every element equals the pivot
- Arrays where all elements are smaller than the pivot
- Arrays where all elements are greater than the pivot
- Arrays containing many repeated pivot values
- Arrays containing negative numbers
- Arrays of length
1
The problem guarantees that the pivot exists in the array, so we never need to handle the case where the pivot is absent.
Approaches
Brute Force Approach
A brute-force strategy would try to repeatedly move elements into their correct regions by swapping or shifting elements in place.
One possible implementation is:
- Scan the array from left to right
- Whenever an element is smaller than the pivot, move it toward the front
- Whenever an element is greater than the pivot, move it toward the back
- Carefully shift elements to preserve relative order
This approach can produce the correct answer because it explicitly constructs the desired ordering while maintaining stability.
However, preserving relative order during repeated insertions or shifts is expensive. Every insertion may require moving many elements, leading to a worst-case time complexity of O(n^2).
With n up to 100000, quadratic behavior becomes too slow.
Optimal Approach
The key observation is that the final array is simply the concatenation of three stable groups:
- Elements less than the pivot
- Elements equal to the pivot
- Elements greater than the pivot
We do not actually need complicated in-place rearrangement. Instead, we can perform a linear scan and collect elements into separate lists.
Because we traverse the original array from left to right, the relative ordering inside each group is automatically preserved.
At the end, we concatenate the three lists together to produce the final answer.
This approach is both simple and efficient.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n²) | O(1) | Uses repeated shifting or insertion operations |
| Optimal | O(n) | O(n) | Stable partition using three temporary lists |
Algorithm Walkthrough
Optimal Algorithm
- Create three empty lists:
lessequalgreater
These lists will store elements according to their relationship with the pivot. 2. Traverse the array from left to right.
Processing elements in original order is critical because the problem requires stable ordering. 3. For each element:
- If the value is smaller than the pivot, append it to
less - If the value equals the pivot, append it to
equal - If the value is greater than the pivot, append it to
greater
- After processing all elements:
-
Concatenate the lists in this order:
-
less + equal + greater
- Return the resulting array.
Why it works
The algorithm maintains a simple invariant during traversal:
lesscontains all previously seen elements smaller than the pivot, in original orderequalcontains all previously seen pivot values, in original ordergreatercontains all previously seen elements larger than the pivot, in original order
Since elements are appended in the same order they are encountered, stability is preserved automatically. Concatenating the three groups produces exactly the required final arrangement.
Python Solution
from typing import List
class Solution:
def pivotArray(self, nums: List[int], pivot: int) -> List[int]:
less = []
equal = []
greater = []
for value in nums:
if value < pivot:
less.append(value)
elif value == pivot:
equal.append(value)
else:
greater.append(value)
return less + equal + greater
The implementation directly follows the algorithm described earlier.
We first initialize three lists to represent the three required regions of the final array.
Next, we iterate through nums exactly once. For every value, we compare it with the pivot and append it into the appropriate list. Because appending preserves insertion order, stability is maintained automatically.
Finally, we concatenate the three lists together and return the result.
The code is concise because Python list operations naturally support this type of stable partitioning.
Go Solution
func pivotArray(nums []int, pivot int) []int {
less := []int{}
equal := []int{}
greater := []int{}
for _, value := range nums {
if value < pivot {
less = append(less, value)
} else if value == pivot {
equal = append(equal, value)
} else {
greater = append(greater, value)
}
}
result := []int{}
result = append(result, less...)
result = append(result, equal...)
result = append(result, greater...)
return result
}
The Go implementation is conceptually identical to the Python version.
One small difference is that Go does not support direct list concatenation using the + operator for slices. Instead, we use repeated append operations with variadic slice expansion syntax:
append(result, less...)
Go slices dynamically resize as needed, making them a natural fit for this problem.
There are no integer overflow concerns because we only compare and copy values.
Worked Examples
Example 1
Input:
nums = [9,12,5,10,14,3,10]
pivot = 10
We process each element one by one.
| Current Value | less | equal | greater |
|---|---|---|---|
| 9 | [9] | [] | [] |
| 12 | [9] | [] | [12] |
| 5 | [9, 5] | [] | [12] |
| 10 | [9, 5] | [10] | [12] |
| 14 | [9, 5] | [10] | [12, 14] |
| 3 | [9, 5, 3] | [10] | [12, 14] |
| 10 | [9, 5, 3] | [10, 10] | [12, 14] |
Final concatenation:
[9,5,3] + [10,10] + [12,14]
Result:
[9,5,3,10,10,12,14]
Example 2
Input:
nums = [-3,4,3,2]
pivot = 2
| Current Value | less | equal | greater |
|---|---|---|---|
| -3 | [-3] | [] | [] |
| 4 | [-3] | [] | [4] |
| 3 | [-3] | [] | [4, 3] |
| 2 | [-3] | [2] | [4, 3] |
Final concatenation:
[-3] + [2] + [4,3]
Result:
[-3,2,4,3]
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | Each element is processed exactly once |
| Space | O(n) | Extra lists store all elements |
The algorithm performs a single pass through the array, giving linear time complexity.
The additional space comes from the three temporary lists. Together, they store exactly n elements, so the total auxiliary space complexity is linear.
Test Cases
from typing import List
class Solution:
def pivotArray(self, nums: List[int], pivot: int) -> List[int]:
less = []
equal = []
greater = []
for value in nums:
if value < pivot:
less.append(value)
elif value == pivot:
equal.append(value)
else:
greater.append(value)
return less + equal + greater
solution = Solution()
# Provided example 1
assert solution.pivotArray(
[9, 12, 5, 10, 14, 3, 10], 10
) == [9, 5, 3, 10, 10, 12, 14]
# Provided example 2
assert solution.pivotArray(
[-3, 4, 3, 2], 2
) == [-3, 2, 4, 3]
# Single element array
assert solution.pivotArray(
[5], 5
) == [5]
# All elements equal to pivot
assert solution.pivotArray(
[7, 7, 7], 7
) == [7, 7, 7]
# All elements smaller than pivot
assert solution.pivotArray(
[1, 2, 3], 10
) == [1, 2, 3]
# All elements greater than pivot
assert solution.pivotArray(
[10, 11, 12], 5
) == [10, 11, 12]
# Multiple pivot occurrences
assert solution.pivotArray(
[5, 1, 5, 2, 5, 3], 5
) == [1, 2, 3, 5, 5, 5]
# Negative numbers
assert solution.pivotArray(
[-5, -1, -3, 0, 2], -1
) == [-5, -3, -1, 0, 2]
# Stability check for greater elements
assert solution.pivotArray(
[8, 6, 7, 5, 3, 0, 9], 5
) == [3, 0, 5, 8, 6, 7, 9]
# Stability check for smaller elements
assert solution.pivotArray(
[4, 1, 3, 2], 3
) == [1, 2, 3, 4]
| Test | Why |
|---|---|
[9,12,5,10,14,3,10] |
Validates standard mixed-case behavior |
[-3,4,3,2] |
Validates handling of negative numbers |
[5] |
Tests minimum input size |
[7,7,7] |
Tests all elements equal to pivot |
[1,2,3] |
Tests array with no greater/equal elements |
[10,11,12] |
Tests array with no smaller/equal elements |
[5,1,5,2,5,3] |
Tests multiple pivot occurrences |
[-5,-1,-3,0,2] |
Tests negative values and ordering |
[8,6,7,5,3,0,9] |
Verifies stable ordering for greater elements |
[4,1,3,2] |
Verifies stable ordering for smaller elements |
Edge Cases
One important edge case occurs when every element equals the pivot. In this situation, the array should remain unchanged. A buggy implementation might accidentally reorder elements or mishandle empty partitions. Our implementation handles this naturally because all values are appended into the equal list, while the other lists remain empty.
Another important case is when all elements belong entirely to one side of the pivot. For example:
nums = [1,2,3]
pivot = 10
Here, every element is smaller than the pivot. Some implementations may incorrectly assume all three groups contain values. Our solution works correctly because empty lists concatenate safely.
A third important edge case involves preserving stability. Consider:
nums = [8,6,7,5,3,0,9]
pivot = 5
The elements greater than the pivot appear originally as:
8,6,7,9
A non-stable partition algorithm could accidentally reorder them. Our implementation preserves their order because elements are appended sequentially during a left-to-right traversal.
Another subtle case involves repeated pivot values appearing throughout the array. For example:
nums = [5,1,5,2,5,3]
The final arrangement must place all pivot values together while preserving the order of non-pivot groups. The three-list approach guarantees this automatically.