**Difficulty:** Medium, **Asked-in:** Google, Facebook, Microsoft, Amazon, Morgan Stanley.

**Key takeaway:**

- An excellent problem to learn problem-solving using various approaches. Two-pointers and hash table solutions are worth exploring.
- One can find several variations of this problem asked during a coding interview.

Given an array of **n** integers and a value **targetSum**, write a program to check whether there is a pair of elements in the array whose sum is equal to targetSum. If yes, return true; otherwise, return false.

- Assume all elements are distinct.
- Values in the array can be both negative and positive.

**Input:** X[] = [-5, 1, -40, 20, 6, 8, 7], targetSum = 15, **Output:** true

Explanation: (7, 8) or (-5, 20) are the pairs with the sum of 15.

**Input:** X[] = [-5, 4, -2, 16, 8, 9], targetSum = 15, **Output:** false

Explanation: There is no pair of elements whose sum is equal to 15.

- Brute force approach using nested loops
- Using sorting and binary search
- Using sorting and two pointers approach
- Efficient approach using hash table

One basic solution is to check each possible pair of elements. If there exists a pair (i, j) with a sum equal to targetSum, we return true. To achieve this: We run two nested loops to explore all possible pairs: the outer loop from i = 0 to n - 2 and the inner loop from j = i + 1 to n - 1.

Inside the inner loop, we check if the sum of the current pair (X[i] and X[j]) is equal to the targetSum. If it is, we return true. By the end of the nested loops, there is no such pair in the array and we return false.

There are two critical questions:

- Why are we running the outer loop until n - 2? The idea is simple: We don't need to consider the last element in the outer loop since it would have already been checked with all the previous elements.
- Why are we starting the inner loop from i + 1? This will help us ensure that each pair of elements is considered only once, so we avoid checking pairs that have already been checked before.

```
bool checkPairSum(int X[], int n, int targetSum)
{
for (int i = 0; i < n - 1; i = i + 1)
{
for (int j = i + 1; j < n; j = j + 1)
{
if (X[i] + X[j] == targetSum)
return true;
}
}
return false;
}
```

```
def checkPairSum(X, n, targetSum):
for i in range(n - 1):
for j in range(i + 1, n):
if X[i] + X[j] == targetSum:
return True
return False
```

We are exploring all possible pairs in the array and doing constant operations for each pair. Total number of possible pairs = nC2 = n(n - 1)/2 = O(n²). So time complexity = O(n²). We are using constant extra space, so space complexity = O(1).

The critical question is: How can we improve the time complexity? On a sorted array, binary search will take O(log n) time. Can we solve this problem using sorting and binary search? Let's think!

For every element X[i], if **targetSum - X[i]** is present in the array, then there exists a pair with targetSum. So one idea is to sort the array and apply binary search to find **targetSum - X[i]** for every element X[i]. If targetSum - X[i] is present, we return true.

- We sort the array in increasing order.
- Now we iterate over each array element X[i] and apply binary search to look for an element with a value targetSum - X[i]. If targetSum - X[i] exists, we return true.
- We return false if there is no such a pair in the array.

```
bool binarySearch(int X[], int l, int r, int key)
{
while (l <= r)
{
int mid = l + (r - l) / 2;
if (X[mid] == key)
return true;
if (X[mid] < key)
l = mid + 1;
else
r = mid - 1;
}
return false;
}
bool checkPairSum(int X[], int n, int targetSum)
{
sort(X, X + n);
for(int i = 0; i < n; i = i + 1)
{
int k = binarySearch(X, 0, n - 1, targetSum - X[i]);
if (k == true)
return true;
}
return false;
}
```

```
def binary_search(X, l, r, key):
while l <= r:
mid = l + (r - l) // 2
if X[mid] == key:
return True
elif X[mid] < key:
l = mid + 1
else:
r = mid - 1
return False
def check_pair_sum(X, n, target_sum):
X.sort()
for i in range(n):
k = binary_search(X, 0, n - 1, target_sum - X[i])
if k:
return True
return False
```

Suppose we are using the O(nlogn) sorting algorithm heap sort and iterative binary search for the implementation. Time complexity = Time complexity of heap sort + n * Time complexity of binary search = O(nlogn) + n* O(logn) = O(nlogn) + O(nlogn) = O(nlogn).

Space complexity = Space complexity of heap sort + Space complexity of the iterative binary search = O(1) + O(1) = O(1).

Can we optimize the above approach further? Instead of applying binary search, can we think some different method to search for a pair in the sorted array? Let's explore!

On a sorted array, sometimes two pointers approach works perfectly. Here is a thought process: Suppose we sort the array and walk two pointers inward from both ends of the array, looking at their sum at each point.

- If the sum is equal to targetSum, we found a pair.
- If the sum is greater than targetSum, then any sum using the larger element will be greater than targetSum. So we move the right pointer inwards towards a smaller sum.
- If the sum is less than targetSum, then any sum using the smaller element is less than targetSum. So we move the left pointer inwards towards a larger sum.
- If both pointers cross each other, then no such pair is present in the array.

Step 1: We sort the array in increasing order.

Step 2: Now we initialize two pointers: l = 0 and r = n - 1.

Step 3: Next, we run a while loop till l < r.

**If X[l] + X[r] == targetSum**, we return true.**If X[l] + X[r] < targetSum**, we increment l by 1 to move towards a larger value of the pair sum. The idea is simple: Array is sorted and all pairs (l, r - 1), (l, r - 2), ..., (l, l + 1) will have sum less than targetSum. So, by incrementing l, we discard these possibilities of pairs in one go.**If X[l] + X[r] > targetSum**, we decrement r by 1 to move towards a smaller value of the pair sum. The idea is simple: Array is sorted and all pairs (l + 1, r), (l + 2, r), ..., (r - 1, r) will have sum greater than targetSum. So, by decrementing r, we discard these possibilities of pairs in one go.

Step 4: By the end of the loop, if we haven't found such a pair in the entire array, we return false.

```
bool checkPairSum(int X[], int n, int targetSum)
{
sort(X, X + n);
int l = 0, r = n - 1;
while (l < r)
{
if (X[l] + X[r] == targetSum)
return true;
else if (X[l] + X[r] < targetSum)
l = l + 1;
else
r = r - 1;
}
return false;
}
```

```
def check_pair_sum(X, n, target_sum):
X.sort()
l = 0
r = n - 1
while l < r:
if X[l] + X[r] == target_sum:
return True
elif X[l] + X[r] < target_sum:
l = l + 1
else:
r = r - 1
return False
```

Suppose we use an in-place O(n log n) sorting algorithm like heap sort. The critical question is: What would be the time complexity of the while loop? Here's an idea: Based on the comparison, we either move the left or right pointer by 1. In the worst case, we will access each array element using the while loop. So the time complexity of the while loop is O(n).

Overall time complexity = Time complexity of heap sort + Time complexity of the while loop = O(n log n) + O(n) = O(n log n). In the code, we are using constant extra space because heap sort is an in-place sorting algorithm. So space complexity is O(1).

In the last two solutions, the time complexity is still in the range of O(nlogn) due to the dominance of the sorting algorithm. The critical question is: Can we optimize further to solve it using linear time complexity? If we observe the above solutions, searching is a critical operation. So one idea would be to use a hash table because the hash table performs searching efficiently in the O(1) average.

Here is an idea: We iterate over each array element and insert element X[i] into the Hash table. Before inserting X[i], we check if the value targetSum - X[i] already exists in the table. If it exists, we have found a pair with a sum equal to targetSum.

- We create a hash table to store array elements.
- Now we run a loop and scan the array for each X[i].
- We check if
**targetSum - X[i]**is present in the hash table or not. If yes, we have found a pair and we return true. If no, we insert X[i] into the Hash table. - If we didn’t find any such pair by the end the loop, return false.

```
bool checkPairSum(int X[], int n, int targetSum)
{
unordered_set<int> hashTable;
for (int i = 0; i < n; i = i + 1)
{
int k = targetSum - X[i];
if (hashTable.find(k) != hashTable.end())
return true;
hashTable.insert(X[i]);
}
return false;
}
```

```
def checkPairSum(X, n, targetSum):
hashTable = set()
for i in range(n):
k = targetSum - X[i]
if k in hashTable:
return True
hashTable.add(X[i])
return False
```

```
public class PairSumChecker
{
public static boolean checkPairSum(int[] X, int n, int targetSum)
{
HashSet<Integer> hashTable = new HashSet<>();
for (int i = 0; i < n; i = i + 1)
{
int k = targetSum - X[i];
if (hashTable.contains(k))
return true;
hashTable.add(X[i]);
}
return false;
}
}
```

In the worst case, we need to scan the whole array to find such a pair. So time complexity = Time complexity of inserting elements into the hash table + Time complexity of searching targetSum - X[i] into the hash table = n * O(1) + n * O(1) = O(n) + O(n) = O(n). Space complexity = O(n), as we are using a hash table of size O(n).

- Is there any other way to solve this problem?
- What would be the time and space complexity of the last approach if we use a binary search tree (BST) instead of a hash table?
- What would be the time and space complexity of the 2nd and 3rd approaches if we use the quicksort or merge sort algorithms?
- Do all the above algorithms work fine if elements are repeated?
- In all the above approaches, do we need to handle the case for negative values separately? How can we modify the above code to return the pair with the targetSum?
- How can we modify the above code to count all pairs with the targetSum?
- What are the differences between Hash Set and Hash Map in Java?
- What are the differences between unordered map and unordered set in C++?

- Nested loops: Time = O(n^2), Space = O(1).
- Sorting and binary search: Time = O(nlogn), Space = O(1).
- Sorting and two pointers: Time = O(nlogn), Space = O(1).
- Hash table: Time = O(n), Space = O(n).

- Find four elements that sum to a given value
- Find a triplet whose sum is equal to zero
- Given two unsorted arrays, find all pairs whose sum is x
- Count all distinct pairs with a difference equal to k
- Find intersection of two unsorted arrays
- Check whether array is subset of another array
- Find if there is a pair with a product equal to x

Please write in the message below if you find anything incorrect, or if you want to share more insight. Enjoy learning, Enjoy algorithms!