Minimize Maximum Pair Sum in Array
MedPrompt
The pair sum of a pair (a,b) is equal to a + b. The maximum pair sum is the largest pair sum in a list of pairs.
- For example, if we have pairs
(1,5),(2,3), and(4,4), the maximum pair sum would bemax(1+5, 2+3, 4+4) = max(6, 5, 8) = 8.
Given an array nums of even length n, pair up the elements of nums into n / 2 pairs such that:
- Each element of
numsis in exactly one pair, and - The maximum pair sum is minimized.
Return the minimized maximum pair sum after optimally pairing up the elements.
Example 1:
Input: nums = [3,5,2,3]
Output: 7
Explanation: The elements can be paired up into pairs (3,3) and (5,2).
The maximum pair sum is max(3+3, 5+2) = max(6, 7) = 7.Example 2:
Input: nums = [3,5,4,2,4,6]
Output: 8
Explanation: The elements can be paired up into pairs (3,5), (4,4), and (6,2).
The maximum pair sum is max(3+5, 4+4, 6+2) = max(8, 8, 8) = 8.
Constraints:
n == nums.length2 <= n <= 105nis even.1 <= nums[i] <= 105
Approaches
2 approaches with complexity analysis and trade-offs.
This approach is based on the intuition that to minimize the maximum pair sum, we should balance the pairs by pairing the smallest elements with the largest ones. Sorting the array allows us to easily identify these elements.
Algorithm
- Sort the input array
numsin non-decreasing order. - Initialize a variable
maxSumto store the maximum pair sum, setting it to 0 initially. - Initialize two pointers:
leftat the beginning of the array (index 0) andrightat the end of the array (indexn-1). - Iterate with a
whileloop as long asleftis less thanright. - Inside the loop, calculate the sum of the elements pointed to by
leftandright:currentSum = nums[left] + nums[right]. - Update
maxSumto be the maximum of its current value andcurrentSum. - Move the pointers closer to the center: increment
leftand decrementright. - After the loop finishes, return
maxSum.
Walkthrough
The core idea is that the optimal pairing strategy involves matching the smallest numbers with the largest numbers. To achieve this, we first sort the array nums in non-decreasing order. After sorting, the smallest element is at nums[0] and the largest is at nums[n-1]. The second smallest is at nums[1] and the second largest is at nums[n-2], and so forth. We can then use a two-pointer technique. One pointer, left, starts at the beginning of the sorted array, and another pointer, right, starts at the end. We form a pair with the elements at these pointers, calculate their sum, and update our running maximum sum. Then, we move both pointers inwards (left++, right--) to consider the next pair of smallest and largest available elements. This process continues until the pointers meet or cross, ensuring all elements are paired up. The final result is the minimized maximum pair sum.
import java.util.Arrays; class Solution { public int minPairSum(int[] nums) { // Step 1: Sort the array Arrays.sort(nums); int maxSum = 0; // Step 3: Initialize two pointers int left = 0; int right = nums.length - 1; // Step 4-7: Iterate and find pair sums while (left < right) { int currentSum = nums[left] + nums[right]; maxSum = Math.max(maxSum, currentSum); left++; right--; } // Step 8: Return the result return maxSum; }}Complexity
Time
O(N log N). The dominant part of this algorithm is sorting the array, which typically takes `O(N log N)` time. The subsequent two-pointer scan to find the pair sums takes linear time, `O(N)`, which is overshadowed by the sorting time.
Space
O(log N) to O(N). The space complexity is determined by the sorting algorithm used. In Java, `Arrays.sort()` for primitive types uses a variant of Quicksort, which requires `O(log N)` space on average for the recursion stack, but can take up to `O(N)` in the worst case.
Trade-offs
Pros
The logic is straightforward and easy to implement.
It's a general solution that works regardless of the range of values in the input array.
Cons
The time complexity of
O(N log N)is not optimal for this problem, given the constraints on the input values.The space complexity depends on the sorting algorithm's implementation and can be
O(N)in the worst case.
This approach leverages the problem's constraint on the range of input values to achieve a linear time solution. By using a frequency array (similar to Counting Sort), we can efficiently find the smallest and largest available numbers to pair up without performing a full comparison-based sort.
Algorithm
- Determine the maximum possible value
Kfrom the input constraints (e.g., 100000). - Create a frequency array
countsof sizeK+1to store the count of each number. - Iterate through the input array
numsand populate thecountsarray. For eachnuminnums, incrementcounts[num]. - Initialize
maxSum = 0. - Initialize two pointers:
lowstarting at 1 andhighstarting atK. - Loop while
low <= high: a. Ifcounts[low]is 0, it means the numberlowis not present or has been used up. Incrementlowand continue. b. Ifcounts[high]is 0, decrementhighand continue. c. If bothcounts[low]andcounts[high]are greater than 0, we have found the current smallest and largest available numbers. d. Calculate their sumlow + highand updatemaxSum = Math.max(maxSum, low + high). e. Decrementcounts[low]andcounts[high]to mark them as used. - Return
maxSum.
Walkthrough
Instead of sorting the array, we can use a more direct method to find the smallest and largest available elements by taking advantage of the value constraints (1 <= nums[i] <= 10^5). We can create a frequency array, counts, to store how many times each number appears in the input nums. The size of this array will be based on the maximum possible value (100001).
After populating the counts array in a single pass over nums, we use two pointers, low and high, initialized to the start (1) and end (100000) of our value range. We move low forward until we find a number with a count greater than zero (the smallest available number). Similarly, we move high backward to find the largest available number. We then pair these two numbers, update our maximum sum, and decrement their counts in the frequency array. This process is repeated until all numbers are paired. This avoids the O(N log N) cost of sorting, leading to a more efficient O(N + K) solution, where K is the range of values.
class Solution { public int minPairSum(int[] nums) { // The maximum value is constrained to 100000 int maxVal = 100000; int[] counts = new int[maxVal + 1]; // Populate the frequency array for (int num : nums) { counts[num]++; } int maxSum = 0; int low = 1; int high = maxVal; // Use two pointers on the frequency array while (low <= high) { // Find the smallest available number if (counts[low] == 0) { low++; continue; } // Find the largest available number if (counts[high] == 0) { high--; continue; } // Form a pair and update maxSum maxSum = Math.max(maxSum, low + high); // Decrement counts for the used numbers counts[low]--; counts[high]--; } return maxSum; }}Complexity
Time
O(N + K), where `N` is the length of `nums` and `K` is the range of values. Populating the `counts` array takes `O(N)`. The two-pointer scan on the `counts` array takes `O(K)` time because the `low` and `high` pointers each traverse the range of values at most once. Thus, the total time complexity is linear.
Space
O(K), where `K` is the maximum possible value in `nums`. We need an auxiliary array `counts` of size `K+1` to store the frequencies of the numbers. Given the constraint `nums[i] <= 10^5`, this is a fixed amount of extra space.
Trade-offs
Pros
Achieves linear time complexity, which is more efficient than the sorting-based approach for the given constraints.
The logic remains intuitive: pair the smallest with the largest.
Cons
This approach is only efficient when the range of values (
K) is manageable. IfKwere very large, the space complexity would become a problem.It is less general than the sorting approach as it relies on the values being non-negative integers within a specific range.
Solutions
Solution
class Solution {public int minPairSum(int[] nums) { Arrays.sort(nums); int ans = 0, n = nums.length; for (int i = 0; i < n >> 1; ++i) { ans = Math.max(ans, nums[i] + nums[n - i - 1]); } return ans; }}/** * @param {number[]} nums * @return {number} */ var minPairSum = function ( nums,) { nums.sort((a, b) => a - b); let ans = 0; const n = nums.length; for (let i = 0; i < n >> 1; ++i) { ans = Math.max(ans, nums[i] + nums[n - 1 - i]); } return ans;};public class Solution { public int MinPairSum(int[] nums) { Array.Sort(nums); int ans = 0, n = nums.Length; for (int i = 0; i < n >> 1; ++i) { ans = Math.Max(ans, nums[i] + nums[n - i - 1]); } return ans; }}class Solution {public: int minPairSum(vector<int> &nums) { sort(nums.begin(), nums.end()); int ans = 0, n = nums.size(); for (int i = 0; i < n >> 1; ++i) { ans = max(ans, nums[i] + nums[n - i - 1]); } return ans; }};class Solution: def minPairSum(self, nums: List[int]) -> int: nums . sort() n = len(nums) return max(x + nums[n - i - 1] for i, x in enumerate(nums[: n >> 1]))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.