5 Best Ways to Find Three Elements from Different Arrays with a Specified Sum in Python

Finding Three Elements from Three Different Arrays with a Specific Sum in Python

πŸ’‘ Problem Formulation: Given three separate arrays, the objective is to find three elements, one from each array, such that their sum is equal to a desired target value. For example, given arrays a = [1, 2, 3], b = [4, 5, 6], c = [7, 8, 9], and a target sum of 18, a valid output could be (3, 6, 9) as their sum equals 18.

Method 1: Brute Force Approach

This method involves iterating over each array and checking all possible combinations to find a solution. While it is straightforward and guaranteed to find a result if it exists, it has a high computational complexity of O(n^3).

Here’s an example:

def find_triplet_brute_force(arr1, arr2, arr3, target):
    for i in arr1:
        for j in arr2:
            for k in arr3:
                if i + j + k == target:
                    return (i, j, k)
    return None

print(find_triplet_brute_force([1, 2, 3], [4, 5, 6], [7, 8, 9], 18))

Output:

(3, 6, 9)

This code loops through each element of the first array, then within that loop, it loops through each element of the second array, and within that loop, it loops through each element of the third array. For each combination, it checks if the sum equals the target. If so, it returns the tuple; otherwise, it continues. If no combination is found, it returns None.

Method 2: Using a Hash Set

The hash set approach involves creating a hash set for one of the arrays and then iterating through the combinations of the other two arrays. This improves performance by cutting down the search space, resulting in a O(n^2) complexity.

Here’s an example:

def find_triplet_hash_set(arr1, arr2, arr3, target):
    set_arr3 = set(arr3)
    for i in arr1:
        for j in arr2:
            if (target - (i + j)) in set_arr3:
                return (i, j, target - (i + j))
    return None

print(find_triplet_hash_set([1, 2, 3], [4, 5, 6], [7, 8, 9], 18))

Output:

(3, 6, 9)

This code snippet improves on the brute force approach by using a hash set for the elements of the third array. After iterating through the combinations of the first two arrays, it checks if the difference between the target sum and the sum of elements from the first two arrays is present in the third array using constant time hash lookup, which significantly reduces the number of required operations.

Method 3: Sorting and Binary Search

This method involves sorting one of the arrays and then using binary search to quickly find the third element needed to reach the target sum. This method lowers the time complexity to O(n^2 log n) because binary search takes O(log n) time for each pair of elements from the first two arrays.

Here’s an example:

import bisect

def find_triplet_binary_search(arr1, arr2, arr3, target):
    arr3.sort()
    for i in arr1:
        for j in arr2:
            complement = target - (i + j)
            k = bisect.bisect_left(arr3, complement)
            if k < len(arr3) and arr3[k] == complement:
                return (i, j, complement)
    return None

print(find_triplet_binary_search([1, 2, 3], [4, 5, 6], [7, 8, 9], 18))

Output:

(3, 6, 9)

In this code block, the third array is sorted initially. For each element in the first two arrays, the code calculates the necessary value to reach the target from the sorted array and performs a binary search for this value. If found, the matching triplet is returned, otherwise the search continues.

Method 4: Two-pointers Technique

With this method, two of the arrays are sorted. Then, a two-pointer technique is applied to find the pair sum in O(n) time for each element of the third array, thus, achieving a reduced complexity of O(n^2). It’s ideal when the input arrays are already sorted or near sorted.

Here’s an example:

def find_triplet_two_pointers(arr1, arr2, arr3, target):
    arr1.sort()
    arr2.sort()
    for k in arr3:
        i, j = 0, len(arr2) - 1
        while i = 0:
            current_sum = arr1[i] + arr2[j] + k
            if current_sum == target:
                return (arr1[i], arr2[j], k)
            elif current_sum < target:
                i += 1
            else:
                j -= 1
    return None

print(find_triplet_two_pointers([1, 2, 3], [4, 5, 6], [7, 8, 9], 18))

Output:

(3, 6, 9)

This method sorts the first two arrays and then iterates over the third. Using two pointers for the first two arrays, it moves either the left pointer rightward (if the sum is too small) or the right pointer leftward (if the sum is too large). This continues until the triplet with the correct sum is found or all pairs are tested.

Bonus One-Liner Method 5: Using itertools and list comprehension

Python’s itertools.product() function can be used in combination with list comprehension for an elegant one-liner approach that calculates all possible combinations and selects the valid one. It is concise but not recommended for large input arrays due to its O(n^3) complexity.

Here’s an example:

from itertools import product

def find_triplet_itertools(arr1, arr2, arr3, target):
    return next(((i, j, k) for i, j, k in product(arr1, arr2, arr3) if i + j + k == target), None)

print(find_triplet_itertools([1, 2, 3], [4, 5, 6], [7, 8, 9], 18))

Output:

(3, 6, 9)

This intriguing one-liner creates an iterator over all combinations of the arrays using itertools.product(), then utilizes a generator expression to check each triplet’s sum against the target, immediately returning the first match found.

Summary/Discussion

  • Method 1: Brute Force Approach. Simple to implement. Works on unsorted arrays. Not efficient for large datasets due to O(n^3) time complexity.
  • Method 2: Using a Hash Set. More efficient for medium-size arrays with time complexity of O(n^2). Trades off memory for speed. Requires additional space for the hash set.
  • Method 3: Sorting and Binary Search. Combines sorting with binary search for a good balance between speed and space. Not as fast as a pure O(n^2) method but requires less space.
  • Method 4: Two-pointers Technique. Highly efficient if arrays are already sorted or nearly sorted. Achieves O(n^2) time complexity. Sorting can add overhead if not already sorted.
  • Bonus One-Liner Method 5: Using itertools and list comprehension. Elegant and concise. However, it’s still a brute force method in disguise with O(n^3) complexity and should be avoided for large arrays.