1877. Minimize Maximum Pair Sum in Array
Problem Description
You are given an array nums
of even length n
. Your task is to pair up all elements in the array into n/2
pairs such that each element belongs to exactly one pair.
For any pair (a, b)
, the pair sum is defined as a + b
. Among all the pairs you create, there will be a maximum pair sum (the largest sum among all pairs).
Your goal is to arrange the pairs in such a way that this maximum pair sum is as small as possible.
For example, if you have the array [1, 2, 3, 4]
:
- One way to pair:
(1, 2)
and(3, 4)
gives pair sums of3
and7
, with maximum =7
- Another way:
(1, 4)
and(2, 3)
gives pair sums of5
and5
, with maximum =5
- The second pairing is better because its maximum pair sum (
5
) is smaller than the first (7
)
The solution uses a greedy strategy: after sorting the array, pair the smallest element with the largest, the second smallest with the second largest, and so on. This approach ensures that we balance out the pairs - avoiding situations where large numbers are paired together, which would create unnecessarily large pair sums.
The code sorts the array, then pairs elements from opposite ends: nums[0]
with nums[n-1]
, nums[1]
with nums[n-2]
, etc. It calculates all these pair sums and returns the maximum among them, which represents the minimized maximum pair sum.
Intuition
The key insight is to think about what happens when we create pairs. If we pair two large numbers together, we get a very large sum. Similarly, pairing two small numbers gives us a small sum, but this wastes the opportunity to use those small numbers to "balance out" the large ones.
Consider what we're trying to minimize: the maximum pair sum. This means we want to avoid creating any pair that's too large. The worst-case scenario would be pairing the two largest numbers together - this would create an unnecessarily large maximum.
So how do we prevent any pair from becoming too large? By ensuring that whenever we include a large number in a pair, we balance it with a small number. This naturally leads us to the strategy of pairing opposites: the largest with the smallest, the second-largest with the second-smallest, and so on.
Why does this work? Think of it as a balancing act. Each large number needs to be "diluted" by pairing it with a small number. If we pair max
with min
, and second_max
with second_min
, we're distributing the "burden" of large numbers evenly across all pairs.
This greedy approach ensures that no single pair bears too much weight. Any other pairing strategy would result in at least one pair having a larger sum - either by putting two relatively large numbers together, or by not optimally balancing the extreme values.
The mathematical reasoning is that for any sorted array, the sum nums[i] + nums[n-1-i]
creates the most balanced pairs, minimizing the maximum among all such sums.
Learn more about Greedy, Two Pointers and Sorting patterns.
Solution Approach
The implementation follows a straightforward greedy algorithm with these steps:
Step 1: Sort the array
nums.sort()
First, we sort the array in ascending order. This arranges the elements so we can easily identify and pair the smallest with the largest elements.
Step 2: Create pairs and find maximum
return max(x + nums[-i - 1] for i, x in enumerate(nums[: len(nums) >> 1]))
This line does several things efficiently:
nums[: len(nums) >> 1]
takes the first half of the sorted array (the smaller elements). The>> 1
is a bitwise right shift, equivalent to dividing by 2.enumerate(nums[: len(nums) >> 1])
iterates through the first half with indices- For each element
x
at indexi
in the first half, we pair it withnums[-i - 1]
from the second half- When
i = 0
: we pairnums[0]
withnums[-1]
(first with last) - When
i = 1
: we pairnums[1]
withnums[-2]
(second with second-to-last) - And so on...
- When
x + nums[-i - 1]
calculates each pair summax(...)
finds the maximum among all these pair sums
Time Complexity: O(n log n)
due to sorting, where n
is the length of the array. The pairing operation itself is O(n/2)
which simplifies to O(n)
.
Space Complexity: O(1)
if we don't count the space used by the sorting algorithm (which might use O(log n)
for the recursion stack in some implementations).
The algorithm leverages the two-pointer pattern conceptually - we're effectively using pointers from both ends of the sorted array moving toward the center, though the implementation uses indexing rather than explicit pointers.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with the array nums = [3, 5, 2, 3]
.
Step 1: Sort the array
After sorting: nums = [2, 3, 3, 5]
Step 2: Create pairs from opposite ends
We'll pair elements from the first half with elements from the second half:
- First half:
[2, 3]
(indices 0, 1) - Second half:
[3, 5]
(indices 2, 3)
Now let's trace through the pairing process:
When i = 0
:
- We take
x = nums[0] = 2
- We pair it with
nums[-0-1] = nums[-1] = 5
- Pair sum:
2 + 5 = 7
When i = 1
:
- We take
x = nums[1] = 3
- We pair it with
nums[-1-1] = nums[-2] = 3
- Pair sum:
3 + 3 = 6
So our pairs are:
(2, 5)
with sum = 7(3, 3)
with sum = 6
Step 3: Find the maximum pair sum
Maximum of [7, 6]
= 7
The algorithm returns 7
as the minimized maximum pair sum.
Why is this optimal? Let's verify by checking other possible pairings:
- If we paired
(2, 3)
and(3, 5)
: sums would be5
and8
, max =8
(worse) - If we paired
(2, 3)
and(3, 5)
: sums would be5
and8
, max =8
(worse)
By pairing smallest with largest, we avoid creating the worst-case sum of 3 + 5 = 8
, and instead balance the pairs to minimize the maximum.
Solution Implementation
1class Solution:
2 def minPairSum(self, nums: List[int]) -> int:
3 # Sort the array in ascending order
4 nums.sort()
5
6 # Get the length of the array
7 n = len(nums)
8
9 # Calculate the maximum pair sum
10 # We pair the smallest elements with the largest elements
11 # to minimize the maximum pair sum
12 max_pair_sum = 0
13
14 # Iterate through the first half of the sorted array
15 for i in range(n // 2):
16 # Pair element at index i with element at index (n - 1 - i)
17 # This pairs smallest with largest, second smallest with second largest, etc.
18 current_pair_sum = nums[i] + nums[n - 1 - i]
19
20 # Update the maximum pair sum if current pair sum is larger
21 max_pair_sum = max(max_pair_sum, current_pair_sum)
22
23 return max_pair_sum
24
1class Solution {
2 public int minPairSum(int[] nums) {
3 // Sort the array in ascending order
4 Arrays.sort(nums);
5
6 // Initialize the maximum pair sum
7 int maxPairSum = 0;
8 int arrayLength = nums.length;
9
10 // Pair the smallest element with the largest, second smallest with second largest, etc.
11 // This greedy approach minimizes the maximum pair sum
12 for (int i = 0; i < arrayLength / 2; i++) {
13 // Calculate the sum of current pair (element at index i and its corresponding element from the end)
14 int currentPairSum = nums[i] + nums[arrayLength - i - 1];
15
16 // Update the maximum pair sum if current pair sum is larger
17 maxPairSum = Math.max(maxPairSum, currentPairSum);
18 }
19
20 // Return the minimized maximum pair sum
21 return maxPairSum;
22 }
23}
24
1class Solution {
2public:
3 int minPairSum(vector<int>& nums) {
4 // Sort the array in ascending order
5 sort(nums.begin(), nums.end());
6
7 // Initialize the maximum pair sum
8 int max_pair_sum = 0;
9 int n = nums.size();
10
11 // Pair the smallest with the largest, second smallest with second largest, etc.
12 // This greedy approach minimizes the maximum pair sum
13 for (int i = 0; i < n / 2; ++i) {
14 // Calculate the sum of current pair (i-th smallest and i-th largest)
15 int current_pair_sum = nums[i] + nums[n - i - 1];
16
17 // Update the maximum pair sum if current pair sum is larger
18 max_pair_sum = max(max_pair_sum, current_pair_sum);
19 }
20
21 return max_pair_sum;
22 }
23};
24
1/**
2 * Finds the minimized maximum pair sum in an array
3 * Strategy: Sort the array and pair smallest with largest elements
4 * @param nums - Array of integers to form pairs
5 * @returns The minimum possible maximum pair sum
6 */
7function minPairSum(nums: number[]): number {
8 // Sort array in ascending order
9 nums.sort((a: number, b: number) => a - b);
10
11 // Track the maximum pair sum
12 let maxPairSum: number = 0;
13
14 // Get array length
15 const arrayLength: number = nums.length;
16
17 // Iterate through first half of array
18 // Pair each element with its corresponding element from the end
19 for (let i: number = 0; i < arrayLength >> 1; i++) {
20 // Calculate sum of current pair (smallest + largest remaining)
21 const currentPairSum: number = nums[i] + nums[arrayLength - 1 - i];
22
23 // Update maximum pair sum if current is larger
24 maxPairSum = Math.max(maxPairSum, currentPairSum);
25 }
26
27 return maxPairSum;
28}
29
Time and Space Complexity
Time Complexity: O(n Γ log n)
The time complexity is dominated by the sorting operation nums.sort()
, which takes O(n Γ log n)
time where n
is the length of the array. After sorting, the code iterates through half of the array (nums[:len(nums) >> 1]
) to calculate pair sums, which takes O(n/2) = O(n)
time. Since O(n Γ log n) + O(n) = O(n Γ log n)
, the overall time complexity is O(n Γ log n)
.
Space Complexity: O(log n)
The space complexity comes from the sorting algorithm. Python's built-in sort()
method uses Timsort, which has a worst-case space complexity of O(n)
but typically uses O(log n)
space for the recursion stack in practice. The generator expression max(x + nums[-i - 1] for i, x in enumerate(nums[:len(nums) >> 1]))
computes values on-the-fly without storing them all at once, so it only uses O(1)
additional space. Therefore, the overall space complexity is O(log n)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Forgetting to Sort the Array
One of the most common mistakes is attempting to pair elements without first sorting the array. The greedy strategy only works when we can systematically pair smallest with largest elements.
Incorrect approach:
def minPairSum(self, nums: List[int]) -> int:
n = len(nums)
max_sum = 0
# Wrong: trying to pair without sorting
for i in range(n // 2):
max_sum = max(max_sum, nums[i] + nums[n - 1 - i])
return max_sum
Why it fails: Without sorting, you're pairing arbitrary elements that happen to be at opposite positions in the original array, which doesn't minimize the maximum pair sum.
2. Integer Overflow in Other Languages
While Python handles large integers automatically, in languages like Java or C++, calculating pair sums might cause integer overflow for large values.
Solution for languages with fixed integer sizes:
// C++ example with overflow protection
int minPairSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
long long maxSum = 0; // Use long long to prevent overflow
int n = nums.size();
for (int i = 0; i < n / 2; i++) {
maxSum = max(maxSum, (long long)nums[i] + nums[n - 1 - i]);
}
return maxSum;
}
3. Off-by-One Errors in Pairing
When pairing elements from opposite ends, it's easy to make indexing mistakes.
Common mistake:
# Wrong: incorrect pairing index
for i in range(n // 2):
current_sum = nums[i] + nums[n - i] # Should be nums[n - 1 - i]
This would cause an index out of bounds error since nums[n]
doesn't exist (arrays are 0-indexed).
4. Modifying the Input Array
The solution sorts the input array in-place, which modifies it. If the original array order needs to be preserved for other operations, this could cause issues.
Solution if original order must be preserved:
def minPairSum(self, nums: List[int]) -> int:
# Create a copy to avoid modifying the original
sorted_nums = sorted(nums) # Creates a new sorted list
n = len(sorted_nums)
max_pair_sum = 0
for i in range(n // 2):
current_pair_sum = sorted_nums[i] + sorted_nums[n - 1 - i]
max_pair_sum = max(max_pair_sum, current_pair_sum)
return max_pair_sum
5. Assuming Odd-Length Arrays
The problem specifies even-length arrays, but if you accidentally test with odd-length arrays or don't validate input, the algorithm will miss one element.
Defensive programming approach:
def minPairSum(self, nums: List[int]) -> int:
n = len(nums)
if n % 2 != 0:
raise ValueError("Array length must be even")
nums.sort()
max_pair_sum = 0
for i in range(n // 2):
current_pair_sum = nums[i] + nums[n - 1 - i]
max_pair_sum = max(max_pair_sum, current_pair_sum)
return max_pair_sum
Which two pointer techniques do you use to check if a string is a palindrome?
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
Tech Interview Pattern Two Pointers Introduction If you prefer videos here's a super quick introduction to Two Pointers div class responsive iframe iframe src https www youtube com embed xZ4AfXHQ1VQ title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture allowfullscreen iframe div Two pointers is a common interview
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
Want a Structured Path to Master System Design Too? Donβt Miss This!