Given an array arr[] and a number target, find a pair of elements (a, b) in arr[], where a ≤ b whose sum is closest to target.
Note: Return the pair in sorted order and if there are multiple such pairs return the pair with maximum absolute difference. If no such pair exists return an empty array.
Examples:
Input: arr[] = [10, 30, 20, 5], target = 25
Output: [5, 20]
Explanation: The pair(5, 20)has sum25, which is exactly equal to the target. Since its sum is closest to the target, the answer is[5, 20].
Input: arr[] = [5, 2, 7, 1, 4], target = 10
Output: [2, 7]
Explanation: As (4, 5), (2, 7) and (4, 7) both are closest to 10, but absolute difference of (4, 5) is 1, (2, 7) is 5 and (4, 7) is 3. Hence, [2, 7] has maximum absolute difference and closest to target.
Input: arr[] = [10], target = 10
Output: [ ]
Explanation: A valid pair requires two elements. Since the array contains only one element, no pair can be formed, so the answer is an empty array.
Table of Content
[Naive Approach] Explore all possible pairs - O(n ^ 2) Time and O(1) Space
The idea is to Check every possible pair in the array. For each pair, compute its sum and compare its distance from the target with the best pair found so far. If multiple pairs are equally close, keep the one with the maximum absolute difference.
#include <iostream>
#include <limits.h>
#include <vector>
using namespace std;
vector<int> sumClosest(vector<int> &arr, int target)
{
int n = arr.size();
vector<int> res;
int minDiff = INT_MAX;
// Generating all possible pairs
for (int i = 0; i < n - 1; i++)
{
for (int j = i + 1; j < n; j++)
{
int currSum = arr[i] + arr[j];
int currDiff = abs(currSum - target);
// if currDiff is less than minDiff, it indicates
// that this pair is closer to the target
if (currDiff < minDiff)
{
minDiff = currDiff;
res = {min(arr[i], arr[j]), max(arr[i], arr[j])};
}
// if currDiff is equal to minDiff, find the one with
// largest absolute difference
else if (currDiff == minDiff && (res[1] - res[0]) < abs(arr[i] - arr[j]))
{
res = {min(arr[i], arr[j]), max(arr[i], arr[j])};
}
}
}
return res;
}
int main()
{
vector<int> arr = {5, 2, 7, 1, 4};
int target = 10;
vector<int> ans = sumClosest(arr, target);
if (ans.empty())
{
cout << "[]";
}
else
{
cout << "[" << ans[0] << ", " << ans[1] << "]";
}
return 0;
}
import java.util.ArrayList;
public class GFG {
public static ArrayList<Integer> sumClosest(int[] arr,
int target)
{
int n = arr.length;
ArrayList<Integer> res = new ArrayList<>();
int minDiff = Integer.MAX_VALUE;
// Generating all possible pairs
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
int currSum = arr[i] + arr[j];
int currDiff = Math.abs(currSum - target);
// if currDiff is less than minDiff, it
// indicates that this pair is closer to the
// target
if (currDiff < minDiff) {
minDiff = currDiff;
res.clear();
res.add(Math.min(arr[i], arr[j]));
res.add(Math.max(arr[i], arr[j]));
}
// if currDiff is equal to minDiff, find the
// one with largest absolute difference
else if (currDiff == minDiff
&& (res.get(1) - res.get(0))
< Math.abs(arr[i]
- arr[j])) {
res.clear();
res.add(Math.min(arr[i], arr[j]));
res.add(Math.max(arr[i], arr[j]));
}
}
}
return res;
}
public static void main(String[] args)
{
int[] arr = { 5, 2, 7, 1, 4 };
int target = 10;
ArrayList<Integer> ans = sumClosest(arr, target);
if (ans.isEmpty()) {
System.out.println("[]");
}
else {
System.out.println("[" + ans.get(0) + ", "
+ ans.get(1) + "]");
}
}
}
def sumClosest(arr, target):
n = len(arr)
res = []
minDiff = float('inf')
# Generating all possible pairs
for i in range(n - 1):
for j in range(i + 1, n):
currSum = arr[i] + arr[j]
currDiff = abs(currSum - target)
# if currDiff is less than minDiff, it indicates
# that this pair is closer to the target
if currDiff < minDiff:
minDiff = currDiff
res = [min(arr[i], arr[j]), max(arr[i], arr[j])]
# if currDiff is equal to minDiff, find the one with
# largest absolute difference
elif currDiff == minDiff and (res[1] - res[0]) < abs(arr[i] - arr[j]):
res = [min(arr[i], arr[j]), max(arr[i], arr[j])]
return res
if __name__ == '__main__':
arr = [5, 2, 7, 1, 4]
target = 10
ans = sumClosest(arr, target)
if not ans:
print('[]')
else:
print('[{}, {}]'.format(ans[0], ans[1]))
using System;
using System.Collections.Generic;
class GFG {
public static List<int> sumClosest(int[] arr,
int target)
{
int n = arr.Length;
List<int> res = new List<int>();
int minDiff = int.MaxValue;
// Generating all possible pairs
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
int currSum = arr[i] + arr[j];
int currDiff = Math.Abs(currSum - target);
// if currDiff is less than minDiff, it
// indicates that this pair is closer to the
// target
if (currDiff < minDiff) {
minDiff = currDiff;
res.Clear();
res.Add(Math.Min(arr[i], arr[j]));
res.Add(Math.Max(arr[i], arr[j]));
}
// if currDiff is equal to minDiff, find the
// one with largest absolute difference
else if (currDiff == minDiff
&& (res[1] - res[0]) < Math.Abs(
arr[i] - arr[j])) {
res.Clear();
res.Add(Math.Min(arr[i], arr[j]));
res.Add(Math.Max(arr[i], arr[j]));
}
}
}
return res;
}
static void Main()
{
int[] arr = { 5, 2, 7, 1, 4 };
int target = 10;
List<int> ans = sumClosest(arr, target);
if (ans.Count == 0) {
Console.WriteLine("[]");
}
else {
Console.WriteLine("[" + ans[0] + ", " + ans[1]
+ "]");
}
}
}
function sumClosest(arr, target)
{
let n = arr.length;
let res = [];
let minDiff = Number.MAX_SAFE_INTEGER;
// Generating all possible pairs
for (let i = 0; i < n - 1; i++) {
for (let j = i + 1; j < n; j++) {
let currSum = arr[i] + arr[j];
let currDiff = Math.abs(currSum - target);
// if currDiff is less than minDiff, it
// indicates that this pair is closer to the
// target
if (currDiff < minDiff) {
minDiff = currDiff;
res = [
Math.min(arr[i], arr[j]),
Math.max(arr[i], arr[j])
];
}
// if currDiff is equal to minDiff, find the one
// with largest absolute difference
else if (currDiff === minDiff
&& (res[1] - res[0])
< Math.abs(arr[i] - arr[j])) {
res = [
Math.min(arr[i], arr[j]),
Math.max(arr[i], arr[j])
];
}
}
}
return res;
}
// Driver Code
let arr = [ 5, 2, 7, 1, 4 ];
let target = 10;
let ans = sumClosest(arr, target);
if (ans.length === 0) {
console.log("[]");
}
else {
console.log("[" + ans[0] + "," + ans[1] + "]");
}
Output
[2, 7]
[Better Approach] Binary Search - O(n * log n) Time and O(1) Space
The idea is to first sort the array, then for each element arr[i], use binary search on the subarray arr[i+1…n-1] to find the element closest to the complement (target - arr[i]). This forms a candidate pair whose sum is close to the target.
While performing binary search, three cases arise:
- If arr[mid] == complement, we've found an exact pair sum equal to target.
- If arr[mid] < complement, move to the right half -> lo = mid + 1.
- If arr[mid] > complement, move to the left half -> hi = mid - 1.
Among all such pairs, track the one with the minimum absolute difference from target. If there's a tie, choose the pair with the maximum absolute difference between its elements.
#include <algorithm>
#include <climits>
#include <iostream>
#include <vector>
using namespace std;
vector<int> sumClosest(vector<int> &arr, int target)
{
int n = arr.size();
if (n < 2)
return {};
sort(arr.begin(), arr.end());
vector<int> ans;
int minDiff = INT_MAX;
int maxGap = -1;
for (int i = 0; i < n - 1; i++)
{
int complement = target - arr[i];
int lo = i + 1, hi = n - 1;
while (lo <= hi)
{
int mid = lo + (hi - lo) / 2;
if (arr[mid] < complement)
lo = mid + 1;
else
hi = mid - 1;
}
// Check the insertion position
if (lo < n)
{
int sum = arr[i] + arr[lo];
int diff = abs(sum - target);
int gap = arr[lo] - arr[i];
if (diff < minDiff || (diff == minDiff && gap > maxGap))
{
minDiff = diff;
maxGap = gap;
ans = {arr[i], arr[lo]};
}
}
// Check the previous position
if (hi > i)
{
int sum = arr[i] + arr[hi];
int diff = abs(sum - target);
int gap = arr[hi] - arr[i];
if (diff < minDiff || (diff == minDiff && gap > maxGap))
{
minDiff = diff;
maxGap = gap;
ans = {arr[i], arr[hi]};
}
}
}
return ans;
}
int main()
{
vector<int> arr = {5, 2, 7, 1, 4};
int target = 10;
vector<int> ans = sumClosest(arr, target);
if (ans.empty())
{
cout << "[]";
}
else
{
cout << "[" << ans[0] << ", " << ans[1] << "]";
}
return 0;
}
import java.util.ArrayList;
import java.util.Arrays;
class GFG {
public static ArrayList<Integer> sumClosest(int[] arr,
int target)
{
int n = arr.length;
if (n < 2)
return new ArrayList<>();
Arrays.sort(arr);
ArrayList<Integer> ans = new ArrayList<>();
int minDiff = Integer.MAX_VALUE;
int maxGap = -1;
for (int i = 0; i < n - 1; i++) {
int complement = target - arr[i];
int lo = i + 1, hi = n - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (arr[mid] < complement)
lo = mid + 1;
else
hi = mid - 1;
}
// Check the insertion position
if (lo < n) {
int sum = arr[i] + arr[lo];
int diff = Math.abs(sum - target);
int gap = arr[lo] - arr[i];
if (diff < minDiff
|| (diff == minDiff && gap > maxGap)) {
minDiff = diff;
maxGap = gap;
ans.clear();
ans.add(arr[i]);
ans.add(arr[lo]);
}
}
// Check the previous position
if (hi > i) {
int sum = arr[i] + arr[hi];
int diff = Math.abs(sum - target);
int gap = arr[hi] - arr[i];
if (diff < minDiff
|| (diff == minDiff && gap > maxGap)) {
minDiff = diff;
maxGap = gap;
ans.clear();
ans.add(arr[i]);
ans.add(arr[hi]);
}
}
}
return ans;
}
public static void main(String[] args)
{
int[] arr = { 5, 2, 7, 1, 4 };
int target = 10;
ArrayList<Integer> ans = sumClosest(arr, target);
if (ans.isEmpty()) {
System.out.println("[]");
}
else {
System.out.println("[" + ans.get(0) + ", "
+ ans.get(1) + "]");
}
}
}
from typing import List
import bisect
def sumClosest(arr, target):
n = len(arr)
if n < 2:
return []
arr.sort()
ans = []
minDiff = float('inf')
maxGap = -1
for i in range(n - 1):
complement = target - arr[i]
lo = bisect.bisect_left(arr, complement, i + 1, n)
hi = lo - 1
# Check the insertion position
if lo < n:
curr_sum = arr[i] + arr[lo]
diff = abs(curr_sum - target)
gap = arr[lo] - arr[i]
if diff < minDiff or (diff == minDiff and gap > maxGap):
minDiff = diff
maxGap = gap
ans = [arr[i], arr[lo]]
# Check the previous position
if hi > i:
curr_sum = arr[i] + arr[hi]
diff = abs(curr_sum - target)
gap = arr[hi] - arr[i]
if diff < minDiff or (diff == minDiff and gap > maxGap):
minDiff = diff
maxGap = gap
ans = [arr[i], arr[hi]]
return ans
if __name__ == '__main__':
arr = [5, 2, 7, 1, 4]
target = 10
ans = sumClosest(arr, target)
if not ans:
print("[]")
else:
print(f"[{ans[0]}, {ans[1]}]")
using System;
using System.Collections.Generic;
class GFG {
public static List<int> sumClosest(int[] arr,
int target)
{
int n = arr.Length;
if (n < 2)
return new List<int>();
Array.Sort(arr);
List<int> ans = new List<int>();
int minDiff = int.MaxValue;
int maxGap = -1;
for (int i = 0; i < n - 1; i++) {
int complement = target - arr[i];
int lo = i + 1, hi = n - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (arr[mid] < complement)
lo = mid + 1;
else
hi = mid - 1;
}
// Check the insertion position
if (lo < n) {
int sum = arr[i] + arr[lo];
int diff = Math.Abs(sum - target);
int gap = arr[lo] - arr[i];
if (diff < minDiff
|| (diff == minDiff && gap > maxGap)) {
minDiff = diff;
maxGap = gap;
ans.Clear();
ans.Add(arr[i]);
ans.Add(arr[lo]);
}
}
// Check the previous position
if (hi > i) {
int sum = arr[i] + arr[hi];
int diff = Math.Abs(sum - target);
int gap = arr[hi] - arr[i];
if (diff < minDiff
|| (diff == minDiff && gap > maxGap)) {
minDiff = diff;
maxGap = gap;
ans.Clear();
ans.Add(arr[i]);
ans.Add(arr[hi]);
}
}
}
return ans;
}
static void Main()
{
int[] arr = { 5, 2, 7, 1, 4 };
int target = 10;
List<int> ans = sumClosest(arr, target);
if (ans.Count == 0) {
Console.WriteLine("[]");
}
else {
Console.WriteLine("[" + ans[0] + ", " + ans[1]
+ "]");
}
}
}
function sumClosest(arr, target)
{
let n = arr.length;
if (n < 2)
return [];
arr.sort((a, b) => a - b);
let ans = [];
let minDiff = Number.MAX_SAFE_INTEGER;
let maxGap = -1;
for (let i = 0; i < n - 1; i++) {
let complement = target - arr[i];
let lo = i + 1, hi = n - 1;
while (lo <= hi) {
let mid = Math.floor(lo + (hi - lo) / 2);
if (arr[mid] < complement)
lo = mid + 1;
else
hi = mid - 1;
}
// Check the insertion position
if (lo < n) {
let sum = arr[i] + arr[lo];
let diff = Math.abs(sum - target);
let gap = arr[lo] - arr[i];
if (diff < minDiff
|| (diff === minDiff && gap > maxGap)) {
minDiff = diff;
maxGap = gap;
ans = [ arr[i], arr[lo] ];
}
}
// Check the previous position
if (hi > i) {
let sum = arr[i] + arr[hi];
let diff = Math.abs(sum - target);
let gap = arr[hi] - arr[i];
if (diff < minDiff
|| (diff === minDiff && gap > maxGap)) {
minDiff = diff;
maxGap = gap;
ans = [ arr[i], arr[hi] ];
}
}
}
return ans;
}
// Driver COde
let arr = [ 5, 2, 7, 1, 4 ];
let target = 10;
let ans = sumClosest(arr, target);
if (ans.length === 0) {
console.log("[]");
}
else {
console.log("[" + ans[0] + "," + ans[1] + "]");
}
Output
[2, 7]
[Expected Approach] Two Pointer Technique - O(n * log n ) Time and O(1) Space
The idea is to first sort the array and use two pointers: left = 0 and right = n - 1. At each step, compute currSum = arr[left] + arr[right] and compare it with the target.
- If currSum < target, increment left to increase the sum.
- If currSum > target, decrement right to decrease the sum.
- If currSum == target, return the current pair immediately, as no pair can have a smaller difference than 0.
Since the search starts with the smallest and largest elements, whenever multiple pairs are equally close to the target, the pair with the maximum absolute difference is encountered first during the traversal. Therefore, no explicit tie-breaking is required.
Let us understand with an example:
Input: arr[] = [5, 2, 7, 1, 4], target = 10
- Sort the array and initialize two pointers: left = 0 and right = n - 1. Initially, res = [] and minDiff = ∞.
- Compare the pair (1, 7). Its sum is 8, so update res = [1, 7] and increment left since 8 < 10.
- Compare (2, 7). Its sum is 9, which is closer to the target, so update res = [2, 7] and increment left.
- Compare (4, 7) and then (4, 5). Both are equally close to the target. Since the pair with the maximum absolute difference is encountered first during the traversal, the current answer remains unchanged.
- The pointers eventually meet, ending the traversal. The final answer is [2, 7].
#include <algorithm>
#include <climits>
#include <iostream>
#include <vector>
using namespace std;
vector<int> sumClosest(vector<int> &arr, int target)
{
sort(arr.begin(), arr.end());
int n = arr.size();
vector<int> res;
int minDiff = INT_MAX;
int left = 0, right = n - 1;
while (left < right)
{
int currSum = arr[left] + arr[right];
// Check if this pair is closer than the closest
// pair so far
if (abs(target - currSum) < minDiff)
{
minDiff = abs(target - currSum);
res = {arr[left], arr[right]};
}
// If this pair has less sum, move to greater values
if (currSum < target)
left++;
// If this pair has more sum, move to smaller values
else if (currSum > target)
right--;
// If this pair has sum = target, return it
else
return res;
}
return res;
}
int main()
{
vector<int> arr = {5, 2, 7, 1, 4};
int target = 10;
vector<int> ans = sumClosest(arr, target);
if (ans.empty())
{
cout << "[]";
}
else
{
cout << "[" << ans[0] << ", " << ans[1] << "]";
}
return 0;
}
import java.util.ArrayList;
import java.util.Arrays;
public class GFG {
public static ArrayList<Integer> sumClosest(int[] arr,
int target)
{
Arrays.sort(arr);
int n = arr.length;
ArrayList<Integer> res = new ArrayList<>();
int minDiff = Integer.MAX_VALUE;
int left = 0, right = n - 1;
while (left < right) {
int currSum = arr[left] + arr[right];
// Check if this pair is closer than the closest
// pair so far
if (Math.abs(target - currSum) < minDiff) {
minDiff = Math.abs(target - currSum);
res.clear();
res.add(arr[left]);
res.add(arr[right]);
}
// If this pair has less sum, move to greater
// values
if (currSum < target)
left++;
// If this pair has more sum, move to smaller
// values
else if (currSum > target)
right--;
// If this pair has sum = target, return it
else
return res;
}
return res;
}
public static void main(String[] args)
{
int[] arr = { 5, 2, 7, 1, 4 };
int target = 10;
ArrayList<Integer> ans = sumClosest(arr, target);
if (ans.isEmpty()) {
System.out.println("[]");
}
else {
System.out.println("[" + ans.get(0) + ", "
+ ans.get(1) + "]");
}
}
}
def sumClosest(arr, target):
arr.sort()
n = len(arr)
res = []
minDiff = float('inf')
left = 0
right = n - 1
while left < right:
currSum = arr[left] + arr[right]
# Check if this pair is closer than the closest
# pair so far
if abs(target - currSum) < minDiff:
minDiff = abs(target - currSum)
res = [arr[left], arr[right]]
# If this pair has less sum, move to greater values
if currSum < target:
left += 1
# If this pair has more sum, move to smaller values
elif currSum > target:
right -= 1
# If this pair has sum = target, return it
else:
return res
return res
if __name__ == '__main__':
arr = [5, 2, 7, 1, 4]
target = 10
ans = sumClosest(arr, target)
if not ans:
print('[]')
else:
print('[{}, {}]'.format(ans[0], ans[1]))
using System;
using System.Collections.Generic;
class GFG {
public static List<int> sumClosest(int[] arr,
int target)
{
Array.Sort(arr);
int n = arr.Length;
List<int> res = new List<int>();
int minDiff = int.MaxValue;
int left = 0, right = n - 1;
while (left < right) {
int currSum = arr[left] + arr[right];
// Check if this pair is closer than the closest
// pair so far
if (Math.Abs(target - currSum) < minDiff) {
minDiff = Math.Abs(target - currSum);
res.Clear();
res.Add(arr[left]);
res.Add(arr[right]);
}
// If this pair has less sum, move to greater
// values
if (currSum < target)
left++;
// If this pair has more sum, move to smaller
// values
else if (currSum > target)
right--;
// If this pair has sum = target, return it
else
return res;
}
return res;
}
static void Main()
{
int[] arr = { 5, 2, 7, 1, 4 };
int target = 10;
List<int> ans = sumClosest(arr, target);
if (ans.Count == 0) {
Console.WriteLine("[]");
}
else {
Console.WriteLine("[" + ans[0] + ", " + ans[1]
+ "]");
}
}
}
function sumClosest(arr, target)
{
arr.sort((a, b) => a - b);
const n = arr.length;
let res = [];
let minDiff = Number.MAX_SAFE_INTEGER;
let left = 0, right = n - 1;
while (left < right) {
const currSum = arr[left] + arr[right];
// Check if this pair is closer than the closest
// pair so far
if (Math.abs(target - currSum) < minDiff) {
minDiff = Math.abs(target - currSum);
res = [ arr[left], arr[right] ];
}
// If this pair has less sum, move to greater values
if (currSum < target) {
left++;
// If this pair has more sum, move to smaller
// values
}
else if (currSum > target) {
right--;
// If this pair has sum = target, return it
}
else {
return res;
}
}
return res;
}
// Driver Code
const arr = [ 5, 2, 7, 1, 4 ];
const target = 10;
const ans = sumClosest(arr, target);
if (ans.length === 0) {
console.log("[]");
}
else {
console.log(`[${ans[0]}, ${ans[1]}]`);
}
Output
[2, 7]