Given an array `Arr` of `N` positive integers and a target sum `X`, the task is to determine if there exist two distinct elements in `Arr` whose sum is exactly `X`. This problem can be approached using various techniques, each with its own time and space complexities. Below, we explore five different approaches along with their explanations, time complexities, and space complexities. Additionally, Python and Java implementations are provided for each approach.
The naive approach involves using two nested loops to check all possible pairs in the array. For each pair, we check if their sum equals `X`.
- Time Complexity: O(N^2)
- Space Complexity: O(1)
def two_sum_naive(arr, X):
N = len(arr)
for i in range(N):
for j in range(i + 1, N):
if arr[i] + arr[j] == X:
return True
return False
public class TwoSumNaive {
public static boolean twoSumNaive(int[] arr, int X) {
int N = arr.length;
for (int i = 0; i < N; i++) {
for (int j = i + 1; j < N; j++) {
if (arr[i] + arr[j] == X) {
return true;
}
}
}
return false;
}
}
First, sort the array. Then, use two pointers: one starting from the beginning (left) and the other from the end (right). If the sum of the elements at these pointers is greater than `X`, move the right pointer leftwards to decrease the sum. If the sum is less, move the left pointer rightwards to increase the sum.
- Time Complexity: O(N log N) due to sorting + O(N) for the two-pointer traversal.
- Space Complexity: O(1)
def two_sum_two_pointers(arr, X):
arr.sort()
left, right = 0, len(arr) - 1
while left < right:
current_sum = arr[left] + arr[right]
if current_sum == X:
return True
elif current_sum < X:
left += 1
else:
right -= 1
return False
import java.util.Arrays;
public class TwoSumTwoPointers {
public static boolean twoSumTwoPointers(int[] arr, int X) {
Arrays.sort(arr);
int left = 0, right = arr.length - 1;
while (left < right) {
int currentSum = arr[left] + arr[right];
if (currentSum == X) {
return true;
} else if (currentSum < X) {
left++;
} else {
right--;
}
}
return false;
}
}
Sort the array. For each element in the array, perform a binary search for `X - arr[i]` in the remaining part of the array.
- Time Complexity: O(N log N) due to sorting + O(N log N) for binary searches.
- Space Complexity: O(1)
import bisect
def two_sum_binary_search(arr, X):
arr.sort()
for i in range(len(arr)):
target = X - arr[i]
j = bisect.bisect_left(arr, target, i + 1)
if j < len(arr) and arr[j] == target:
return True
return False
import java.util.Arrays;
public class TwoSumBinarySearch {
public static boolean twoSumBinarySearch(int[] arr, int X) {
Arrays.sort(arr);
for (int i = 0; i < arr.length; i++) {
int target = X - arr[i];
int j = Arrays.binarySearch(arr, i + 1, arr.length, target);
if (j > i) {
return true;
}
}
return false;
}
}
Use a hash set to store elements of the array. For each element, check if `X - arr[i]` is already in the set. If found, the pair exists.
- Time Complexity: O(N)
- Space Complexity: O(N)
def two_sum_hashing(arr, X):
seen = set()
for num in arr:
if X - num in seen:
return True
seen.add(num)
return False
import java.util.HashSet;
public class TwoSumHashing {
public static boolean twoSumHashing(int[] arr, int X) {
HashSet<Integer> seen = new HashSet<>();
for (int num : arr) {
if (seen.contains(X - num)) {
return true;
}
seen.add(num);
}
return false;
}
}
Count elements based on their remainders when divided by `X`. Check for pairs of remainders that sum to `X`.
- Time Complexity: O(N)
- Space Complexity: O(X)
def two_sum_remainders(arr, X):
remainder_counts = [0] X
for num in arr:
remainder_counts[num % X] += 1
if remainder_counts[0] > 1:
return True
for i in range(1, X // 2 + 1):
if i != X - i:
if remainder_counts[i] > 0 and remainder_counts[X - i] > 0:
return True
else:
if remainder_counts[i] > 1:
return True
return False
public class TwoSumRemainders {
public static boolean twoSumRemainders(int[] arr, int X) {
int[] remainderCounts = new int[X];
for (int num : arr) {
remainderCounts[num % X]++;
}
if (remainderCounts[0] > 1) {
return true;
}
for (int i = 1; i <= X / 2; i++) {
if (i != X - i) {
if (remainderCounts[i] > 0 && remainderCounts[X - i] > 0) {
return true;
}
} else {
if (remainderCounts[i] > 1) {
return true;
}
}
}
return false;
}
}
These five approaches provide different ways to solve the problem of finding two numbers in an array that sum to a given value `X`. Each method has its advantages and trade-offs in terms of time and space complexity. Depending on the size of the array and the constraints, one approach may be more suitable than the others.