You are given a 0-indexed integer array nums and an integer p. Find p pairs of indices of nums such that the maximum difference amongst all the pairs is minimized. Also, ensure no index appears more than once amongst the p pairs.
Note that for a pair of elements at the index i and j, the difference of this pair is |nums[i] - nums[j]|, where |x| represents the absolute value of x.
Return the minimum maximum difference among all p pairs. We define the maximum of an empty set to be zero.
Example 1:
Input: nums = [10,1,2,7,1,3], p = 2
Output: 1Explanation: The first pair is formed from the indices 1 and 4, and the second pair is formed from the indices 2 and 5.
The maximum difference is max(|nums[1] - nums[4]|, |nums[2] - nums[5]|) = max(0, 1) = 1. Therefore, we return 1.
Example 2:
Input: nums = [4,2,1,2], p = 1
Output: 0Explanation: Let the indices 1 and 3 form a pair. The difference of that pair is |2 - 2| = 0, which is the minimum we can attain.
Constraints:
1 <= nums.length <= 100,0001 <= nums[i] <= 1,000,000,0000 <= p <= (nums.length)/2Before attempting this problem, you should be comfortable with:
To minimize the maximum difference among p pairs, we first sort the array. After sorting, optimal pairs are always adjacent elements because non-adjacent pairs would have larger differences. The problem becomes selecting p non-overlapping adjacent pairs to minimize the largest difference.
This is a classic DP problem: at each position, we decide whether to pair the current element with the next one (taking them both) or skip the current element. The goal is to minimize the maximum difference among all selected pairs.
dfs(i, pairs) as the minimum possible maximum difference when considering elements from index i onward and needing pairs more pairs.pairs == p, return 0 (no more pairs needed).i >= n - 1, return infinity (cannot form more pairs).i and i+1, recursively solve for i+2 with one fewer pair needed. The result is the max of this pair's difference and the recursive result.i+1 without pairing.min of take and skip.class Solution:
def minimizeMax(self, nums: List[int], p: int) -> int:
n = len(nums)
nums.sort()
dp = {}
def dfs(i, pairs):
if pairs == p:
return 0
if i >= n - 1:
return float('inf')
if (i, pairs) in dp:
return dp[(i, pairs)]
take = max(nums[i + 1] - nums[i], dfs(i + 2, pairs + 1))
skip = dfs(i + 1, pairs)
dp[(i, pairs)] = min(take, skip)
return dp[(i, pairs)]
return dfs(0, 0)Where is the size of the input array and is the number of pairs to select.
The same logic as the top-down approach, but we fill the DP table iteratively from the end of the array backward. At each position and pair count, we compute the minimum maximum difference achievable.
dp[i][pairs] represents the minimum maximum difference starting from index i with pairs pairs still needed.dp[i][0] = 0 for all i (no pairs needed means 0 difference).i = n - 2 down to 0:1 to p:max(nums[i+1] - nums[i], dp[i+2][pairs-1])dp[i+1][pairs]min of take and skip.dp[0][p].class Solution:
def minimizeMax(self, nums: List[int], p: int) -> int:
n = len(nums)
nums.sort()
dp = [[float('inf')] * (p + 1) for _ in range(n + 1)]
for i in range(n + 1):
dp[i][0] = 0
for i in range(n - 2, -1, -1):
for pairs in range(1, p + 1):
take = float('inf')
if i + 1 < n:
take = max(nums[i + 1] - nums[i], dp[i + 2][pairs - 1])
skip = dp[i + 1][pairs]
dp[i][pairs] = min(take, skip)
return dp[0][p]Where is the size of the input array and is the number of pairs to select.
Since each row of the DP table only depends on the next two rows, we can reduce space by keeping only three 1D arrays instead of the full 2D table. We rotate these arrays as we iterate backward through the array.
dp, dp1, and dp2 of size p + 1, all initialized to infinity except index 0 which is 0.i = n - 1 down to 0:pairs from 1 to p:max(nums[i+1] - nums[i], dp2[pairs-1]) if i + 1 < ndp1[pairs]dp[pairs] = min(take, skip)dp2 = dp1, dp1 = dp, reset dp.dp1[p].class Solution:
def minimizeMax(self, nums: List[int], p: int) -> int:
n = len(nums)
nums.sort()
dp = [float('inf')] * (p + 1)
dp1 = [float('inf')] * (p + 1)
dp2 = [float('inf')] * (p + 1)
dp[0] = dp1[0] = dp2[0] = 0
for i in range(n - 1, -1, -1):
for pairs in range(1, p + 1):
take = float('inf')
if i + 1 < n:
take = max(nums[i + 1] - nums[i], dp2[pairs - 1])
skip = dp1[pairs]
dp[pairs] = min(take, skip)
dp2 = dp1[:]
dp1 = dp[:]
dp = [float('inf')] * (p + 1)
dp[0] = 0
return dp1[p]Where is the size of the input array and is the number of pairs to select.
Instead of DP, we can binary search on the answer. Given a threshold t, we greedily check if we can form p pairs where each pair has difference at most t. After sorting, we scan left to right: whenever two adjacent elements have difference at most t, we pair them and skip both. This greedy approach works because pairing earlier elements never blocks better options later.
The answer lies between 0 and max - min of the sorted array, so we binary search to find the smallest threshold that allows forming p pairs.
p == 0, return 0.0 and nums[n-1] - nums[0]:mid, check if we can greedily form p pairs:nums[i+1] - nums[i] <= mid, count a pair and skip to i+2. Otherwise move to i+1.p, the threshold is valid.class Solution:
def minimizeMax(self, nums: List[int], p: int) -> int:
if p == 0:
return 0
def isValid(threshold):
i, cnt = 0, 0
while i < len(nums) - 1:
if abs(nums[i] - nums[i + 1]) <= threshold:
cnt += 1
i += 2
else:
i += 1
if cnt == p:
return True
return False
nums.sort()
l, r = 0, nums[-1] - nums[0]
res = nums[-1] - nums[0]
while l <= r:
m = l + (r - l) // 2
if isValid(m):
res = m
r = m - 1
else:
l = m + 1
return resWhere is the size of the input array and is the maximum value in the array.
Optimal pairs in this problem are always adjacent elements in the sorted array. If you try to form pairs without sorting, you might pair elements that are far apart in value, leading to suboptimal or incorrect results. Always sort the array before applying either the DP or binary search approach.
When validating a threshold in the binary search approach, you must skip both elements when forming a pair (move to i + 2), not just one. A common bug is incrementing by 1 after forming a pair, which would allow the same element to be used in multiple pairs. Remember: if nums[i] and nums[i+1] form a valid pair, jump to index i + 2 to ensure non-overlapping pairs.
When p = 0, no pairs need to be formed, so the answer is always 0 regardless of the array contents. Some solutions fail to handle this edge case and may return incorrect results or encounter errors when attempting to form zero pairs. Always check for p == 0 at the start and return 0 immediately.