Cracking the LeetCode Two Sum Variations - All 5 Problems

Author: Sadman Kabir Soumik

Original Two Sum Problem

Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target. You may assume that each input would have exactly one solution, and you may not use the same element twice. You can return the answer in any order.

 1Example 1:
 2Input: nums = [2,7,11,15], target = 9
 3Output: [0,1]
 4Explanation: Because nums[0] + nums[1] == 9, we return [0, 1].
 5
 6Example 2:
 7Input: nums = [3,2,4], target = 6
 8Output: [1,2]
 9
10Example 3:
11Input: nums = [3,3], target = 6
12Output: [0,1]

Brute Force

1class Solution:
2    def twoSum(self, nums: List[int], target: int) -> List[int]:
3        n = len(nums)
4        for i in range(n):
5            for j in range(i+1, n):
6                if nums[i] + nums[j] == target:
7                    return [i, j]

Time complexity: O(n^2); n is the length of the input array. Space complexity: O(1); as we are only using a few extra variables and not using any extra data structures to store intermediate results.

Optimized

 1class Solution:
 2    def twoSum(self, nums: List[int], target: int) -> List[int]:
 3
 4        num_map = {}   # put numbers as key and index as values
 5        # Enumerate through the list 'nums'. 'enumerate' gives us an
 6        # index (idx) and the item at that index (num)
 7		# For example, if nums = [2, 7, 11, 15],
 8        # after this loop, num_map = {2: 0, 7: 1, 11: 2, 15: 3}
 9        for idx, num in enumerate(nums):
10            # key: value = number, index
11            num_map[num] = idx
12
13        for idx, num in enumerate(nums):
14            # Calculate the complement of the current number
15            # (i.e., the difference between 'target' and this number).
16            com = target - num
17            # If the complement exists in the dictionary 'num_map'
18            # and it's not the current number...
19            if com in num_map and idx != num_map[com]:
20                return [idx, num_map[com]]

Time Complexity: O(n); The code includes a single loop that iterates over the entirety of the input array 'arr' (where 'n' is the length of 'arr'). The operations within this loop - dictionary lookups and updates - each have a constant time complexity of O(1). Therefore, the overall time complexity remains linear, i.e., O(n).

Space Complexity: O(n); The code uses a dictionary to store the indices of all elements in the input array 'arr'. Since the size of this dictionary directly scales with the size of the input array 'arr', the space complexity is O(n).

Variant 1: Data Structure Design

This is a LeetCode premium problem.

Design and implement a TwoSum class. It should support the following operations: add and find. add - Add the number to an internal data structure. find - Find if there exists any pair of numbers which sum is equal to the value.

1For example,
2add(1); add(3); add(5);
3find(4) -> true
4find(7) -> false
 1class TwoSum:
 2    def __init__(self):
 3        self.numbers = []
 4
 5    def add(self, number):
 6        self.numbers.append(number)
 7
 8    def find(self, target):
 9        seen = set()
10        for num in self.numbers:
11            complement = target - num
12            if complement in seen:
13                return True
14            seen.add(num)
15        return False

Variant 2 - Two Sum II - Input Array Is Sorted

Given a 1-indexed array of integers numbers that is already *sorted in non-decreasing order*, find two numbers such that they add up to a specific target number. Let these two numbers be numbers[index1] and numbers[index2] where 1 <= index1 < index2 < numbers.length. Return the indices of the two numbers, index1 and index2, added by one as an integer array [index1, index2] of length 2. The tests are generated such that there is exactly one solution. You may not use the same element twice. Your solution must use only constant extra space.

Example 1:

1Input: numbers = [2,7,11,15], target = 9
2Output: [1,2]
3Explanation: The sum of 2 and 7 is 9. Therefore, index1 = 1, index2 = 2. We return [1, 2].

Example 2:

1Input: numbers = [2,3,4], target = 6
2Output: [1,3]
3Explanation: The sum of 2 and 4 is 6. Therefore index1 = 1, index2 = 3. We return [1, 3].
 1class Solution:
 2    def twoSum(self, numbers: List[int], target: int) -> List[int]:
 3        left, right = 0, len(numbers) - 1
 4        while left < right:
 5            current_sum = numbers[left] + numbers[right]
 6            if current_sum > target:
 7                right -= 1
 8            elif current_sum < target:
 9                left += 1
10            else:
11                return [left + 1, right + 1]

Variant 3 - Two Sum Less Than K

This is a LeetCode premium problem.

Given an array A of integers and integer K, return the maximum S such that there exists i < j with A[i] + A[j] = S and S < K. If no i, j exist satisfying this equation, return -1.

 1Example 1:
 2Input: A = [34,23,1,24,75,33,54,8], K = 60
 3Output: 58
 4Explanation:
 5We can use 34 and 24 to sum 58 which is less than 60.
 6
 7Example 2:
 8Input: A = [10,20,30], K = 15
 9Output: -1
10Explanation:
11In this case it's not possible to get a pair sum less that 15.

Brute Force

 1# comparing all pairs
 2def max_sum_less_than_k(A, K):
 3    n = len(A)
 4    max_sum = -1
 5
 6    for i in range(n):
 7        for j in range(i + 1, n):
 8            current_sum = A[i] + A[j]
 9            if current_sum < K and current_sum > max_sum:
10                max_sum = current_sum
11
12    return max_sum

Time complexity: O(n^2) Space complexity: O(1)

Optimized

 1# using two pointers
 2def max_sum_less_than_k(A, K):
 3    A.sort()  # sort the array in ascending order
 4    n = len(A)
 5    max_sum = -1
 6    left = 0  # pointer starting from the left
 7    right = n - 1  # pointer starting from the right
 8
 9    while left < right:
10        current_sum = A[left] + A[right]
11        if current_sum < K:
12            #  # update max_sum if necessary
13            max_sum = max(max_sum, current_sum)
14            # move the left pointer to the right
15            # so that we can make larger sum
16            left += 1
17        else:
18            # move the right pointer to the left
19            right -= 1
20
21    return max_sum

Time complexity: O(n log n) due to the initial sorting step. Space complexity: O(1)

Author: Sadman Kabir Soumik

Posts in this Series

comments powered by Disqus