Array Partition
EasyPrompt
Given an integer array nums of 2n integers, group these integers into n pairs (a1, b1), (a2, b2), ..., (an, bn) such that the sum of min(ai, bi) for all i is maximized. Return the maximized sum.
Example 1:
Input: nums = [1,4,3,2]
Output: 4
Explanation: All possible pairings (ignoring the ordering of elements) are:
1. (1, 4), (2, 3) -> min(1, 4) + min(2, 3) = 1 + 2 = 3
2. (1, 3), (2, 4) -> min(1, 3) + min(2, 4) = 1 + 2 = 3
3. (1, 2), (3, 4) -> min(1, 2) + min(3, 4) = 1 + 3 = 4
So the maximum possible sum is 4.Example 2:
Input: nums = [6,2,6,5,1,2]
Output: 9
Explanation: The optimal pairing is (2, 1), (2, 5), (6, 6). min(2, 1) + min(2, 5) + min(6, 6) = 1 + 2 + 6 = 9.
Constraints:
1 <= n <= 104nums.length == 2 * n-104 <= nums[i] <= 104
Approaches
2 approaches with complexity analysis and trade-offs.
The core idea is based on the realization that to maximize the sum of minimums, we should pair smaller numbers with other smaller numbers. Specifically, if we pair the smallest number with the second smallest, the third smallest with the fourth smallest, and so on, we achieve the maximum possible sum. This is because any other pairing would force a smaller number to be paired with a much larger number, effectively "wasting" the potential of that larger number, as only the smaller one contributes to the sum.
Algorithm
-
- Sort the input array
numsin non-decreasing order.
- Sort the input array
-
- Initialize a variable
sumto 0.
- Initialize a variable
-
- Loop through the sorted array from index 0 to
nums.length - 1with a step of 2.
- Loop through the sorted array from index 0 to
-
- In each iteration, add the element
nums[i]tosum.
- In each iteration, add the element
-
- After the loop finishes, return
sum.
- After the loop finishes, return
Walkthrough
The algorithm first sorts the input array nums in ascending order. After sorting, the array nums will be [s_1, s_2, s_3, s_4, ..., s_{2n-1}, s_{2n}], where s_i <= s_{i+1}. The optimal pairs are (s_1, s_2), (s_3, s_4), ..., (s_{2n-1}, s_{2n}). The sum of minimums for these pairs is min(s_1, s_2) + min(s_3, s_4) + ... + min(s_{2n-1}, s_{2n}). Since the array is sorted, min(s_{2i-1}, s_{2i}) is always s_{2i-1}. Therefore, the maximum sum is the sum of all elements at even indices (0, 2, 4, ...) in the sorted array. We can iterate through the sorted array with a step of 2 and accumulate these elements.
import java.util.Arrays; class Solution { public int arrayPairSum(int[] nums) { // Sort the array in non-decreasing order. Arrays.sort(nums); int maxSum = 0; // Iterate through the sorted array, taking every second element. // These are the smaller elements of each optimal pair. for (int i = 0; i < nums.length; i += 2) { maxSum += nums[i]; } return maxSum; }}Complexity
Time
O(N log N), where N is the number of elements in the array (`2n`). The `Arrays.sort()` method in Java for primitive types uses a dual-pivot quicksort, which has an average time complexity of `O(N log N)`. The subsequent loop takes `O(N)` time. Thus, the sorting step dominates.
Space
O(log N) or O(N). The space complexity of `Arrays.sort()` in Java depends on the implementation. For primitive types, it's an in-place quicksort which requires `O(log N)` space for the recursion stack. In the worst case, it can be `O(N)`.
Trade-offs
Pros
Simple to understand and implement.
Works for any range of integer values, not just the constrained one.
Cons
Not the most efficient solution possible due to the
O(N log N)sorting time.
Given that the values in the input array are within a fixed and relatively small range (-10^4 to 10^4), we can use a more efficient sorting technique than comparison-based sorting. A counting sort or a similar frequency-counting method can sort the elements in linear time. This approach avoids the O(N log N) bottleneck of general-purpose sorting algorithms.
Algorithm
-
- Define a constant
OFFSET = 10000and create an integer arraycountsof size2 * OFFSET + 1.
- Define a constant
-
- Iterate through the input
numsarray. For eachnum, incrementcounts[num + OFFSET].
- Iterate through the input
-
- Initialize
maxSum = 0and a booleanisFirstInPair = true.
- Initialize
-
- Iterate from
i = 0tocounts.length - 1.
- Iterate from
-
- Inside this loop, have a
whileloop that runs as long ascounts[i] > 0.
- Inside this loop, have a
-
- Inside the
whileloop:
- If
isFirstInPairis true, add the current number (i - OFFSET) tomaxSum. - Flip the value of
isFirstInPair. - Decrement
counts[i].
- Inside the
-
- After the loops complete, return
maxSum.
- After the loops complete, return
Walkthrough
The strategy is the same as the first approach: sum the elements that would be at even indices in a sorted version of the array. However, instead of explicitly sorting, we generate the sorted sequence on the fly using a frequency map.
- Create a frequency array, let's call it
counts, to store the number of occurrences of each integer. Since the numbers can be negative, we use an offset. The range is[-10000, 10000], so we can use an array of size20001and an offset of10000.counts[num + 10000]will store the frequency ofnum. - Populate the
countsarray by iterating through the inputnums. - Iterate through the numbers from
-10000to10000. For each number, we process its occurrences. - We need to simulate pairing. We can use a boolean flag, say
isFirstInPair, which starts astrue. When we encounter a number, we add it to the sum ifisFirstInPairistrue, then flip the flag. We do this for each occurrence of the number. - This process effectively walks through the sorted sequence of numbers and picks every other one to add to the sum.
class Solution { public int arrayPairSum(int[] nums) { // The range of numbers is [-10000, 10000]. // We create a frequency array to count occurrences. // The size is 20001 to cover the range. // An offset of 10000 is used to map numbers to non-negative indices. // index = num + 10000 int[] counts = new int[20001]; for (int num : nums) { counts[num + 10000]++; } int maxSum = 0; // This flag helps us pick every other element from the sorted sequence. // 'true' means we are at an even-indexed position (0, 2, 4...) in the sorted list. boolean isFirstInPair = true; // Iterate through the possible numbers from -10000 to 10000. for (int i = 0; i < counts.length; i++) { // While there are occurrences of the number `i - 10000` while (counts[i] > 0) { if (isFirstInPair) { // This number is at an even position in the sorted list. // Add it to the sum. maxSum += (i - 10000); } // Toggle the flag for the next number in the sorted sequence. isFirstInPair = !isFirstInPair; // Decrement the count for this number. counts[i]--; } } return maxSum; }}Complexity
Time
O(N + K), where N is the number of elements in `nums` and K is the range of possible values (`20001`). The first loop to populate the `counts` array takes `O(N)`. The second nested loop structure might look complex, but the inner `while` loop altogether runs exactly `N` times across all iterations of the outer `for` loop. So, the second part is `O(N + K)`. Since K is a constant, the overall complexity is `O(N)`.
Space
O(K), where K is the range of values. We use an auxiliary array of size `20001` to store frequencies. Since K is constant based on the problem constraints, this can be considered O(1) space.
Trade-offs
Pros
More efficient than the comparison-based sorting approach with a linear time complexity.
Cons
The space complexity depends on the range of numbers. If the range were much larger, this approach would become impractical due to memory constraints.
Slightly more complex to implement than the direct sorting approach.
Solutions
Solution
class Solution { public int arrayPairSum ( int [] nums ) { Arrays . sort ( nums ); int ans = 0 ; for ( int i = 0 ; i < nums . length ; i += 2 ) { ans += nums [ i ]; } return ans ; } }/** * @param {number[]} nums * @return {number} */ var arrayPairSum = function ( nums,) { nums.sort((a, b) => a - b); let ans = 0; for (let i = 0; i < nums.length; i += 2) { ans += nums[i]; } return ans;};class Solution { public: int arrayPairSum ( vector < int >& nums ) { sort ( nums . begin (), nums . end ()); int ans = 0 ; for ( int i = 0 ; i < nums . size (); i += 2 ) ans += nums [ i ]; return ans ; } };class Solution : def arrayPairSum ( self , nums : List [ int ]) -> int : return sum ( sorted ( nums )[:: 2 ])Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.