Solutions
1. Brute Force
O(n²) time | O(1) space
Intuition
We can check every possible pair of numbers in the array and return the one that sums up to the target.
To get all the possible pairs we will use two nested loops over the whole array.
Algorithm
- Iterate through the outer loop from the first element to the last element with
iindex. - For each outer loop iteration, iterate through the inner loop from the element at
i + 1to the last element withjindex. - Check if the sum of an element at index
iand an element at indexjis equal to the target, return the indexes if it is.
A naive approach would iterate both loops from the first element to the last one. However, we only need to check unordered pairs (combinations) since [i, j] gives the same sum as [j, i]. So we do not check indexes before i as they have already been paired with all the other indexes in the previous iterations. Also, from the problem description we can't use the same index twice, so we skip i itself and start from i + 1.
Code
def twoSum(nums: list[int], target: int) -> list[int]:
for i in range(len(nums)):
for j in range(i + 1, len(nums)):
if nums[i] + nums[j] == target:
return [i, j]
raise ValueError('no answer')/**
* @param {number[]} nums
* @param {number} target
* @returns {number[]}
*/
var twoSum = function (nums, target) {
for (let i = 0; i < nums.length; i++) {
for (let j = i + 1; j < nums.length; j++) {
if (nums[i] + nums[j] === target) return [i, j]
}
}
throw new Error('no answer')
}class Solution {
public int[] twoSum(int[] nums, int target) {
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
if (nums[i] + nums[j] == target) return new int[] { i, j };
}
}
throw new IllegalArgumentException("no answer");
}
}2. Sorting and Two Pointers
O(nlogn) time | O(n) space
Intuition
If we sort the array first, we can use one loop with two indexes starting at each side of the array instead of checking every possible pair.
If the sum of the elements at those indexes is greater than the target, we can skip the right element completely as all other pairs with the right element will make the sum only greater. In the same way we can skip the left element if the sum is less than the target.
Algorithm
- Create a new sorted array with the same elements, keeping the original index of each element.
- Set the
leftindex to the first element and therightindex to the last element. - Iterate through the loop while
leftis less thanrightchecking the sum of two elements onleftandrightindexes.- If the sum is equal to the target, return the original indexes.
- If the sum is less than the target, move
leftindex to the rightleft = left + 1. - If the sum is greater than the target, move
rightindex to the leftright = right - 1.
Code
def twoSum(nums: list[int], target: int) -> list[int]:
pairs = sorted((n, i) for i, n in enumerate(nums))
left, right = 0, len(nums) - 1
while left < right:
total = pairs[left][0] + pairs[right][0]
if total == target:
return [pairs[left][1], pairs[right][1]]
if total < target:
left += 1
else:
right -= 1
raise ValueError('no answer')/**
* @param {number[]} nums
* @param {number} target
* @returns {number[]}
*/
var twoSum = function (nums, target) {
const pairs = nums.map((n, i) => [n, i]).sort((a, b) => a[0] - b[0]);
let left = 0, right = nums.length - 1;
while (left < right) {
const total = pairs[left][0] + pairs[right][0];
if (total === target) return [pairs[left][1], pairs[right][1]];
if (total < target) left++;
else right--;
}
throw new Error('no answer');
}class Solution {
public int[] twoSum(int[] nums, int target) {
int[][] pairs = new int[nums.length][2];
for (int i = 0; i < nums.length; i++) {
pairs[i][0] = nums[i];
pairs[i][1] = i;
}
java.util.Arrays.sort(pairs, (a, b) -> Integer.compare(a[0], b[0]));
int left = 0, right = nums.length - 1;
while (left < right) {
int total = pairs[left][0] + pairs[right][0];
if (total == target) return new int[] { pairs[left][1], pairs[right][1] };
if (total < target) left++;
else right--;
}
throw new IllegalArgumentException("no answer");
}
}3. Hash Table
O(n) time | O(n) space
Intuition
We can iterate through the array with one loop. At each iteration we check if for that element there is a pair in the array that sums up to the target.
To check if the pair exists in the array in O(1) time we will use a hash table.
Algorithm
- Create an empty hash table.
- Iterate through the loop from the first element to the last element with
iindex. - Check if the needed pair
target - nums[i]exists in the hash table, return the indexes if it does. - Add the element to the hash table,
nums[i]as a key andias a value.
A naive approach would use two passes, adding all the elements to a hash table first and then starting another loop to find the pair. However, adding elements to the hash table on the fly while iterating still guarantees we check all the possible pair combinations.
Code
def twoSum(nums: list[int], target: int) -> list[int]:
seen = {}
for i, n in enumerate(nums):
if target - n in seen:
return [seen[target - n], i]
seen[n] = i
raise ValueError('no answer')/**
* @param {number[]} nums
* @param {number} target
* @returns {number[]}
*/
var twoSum = function (nums, target) {
const seen = new Map()
for (let i = 0; i < nums.length; i++) {
if (seen.has(target - nums[i])) return [seen.get(target - nums[i]), i]
seen.set(nums[i], i)
}
throw new Error('no answer')
}import java.util.HashMap;
import java.util.Map;
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> seen = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
Integer j = seen.get(target - nums[i]);
if (j != null) return new int[] { j, i };
seen.put(nums[i], i);
}
throw new IllegalArgumentException("no answer");
}
}def twoSum(nums: list[int], target: int) -> list[int]: pass Press Visualise to step through your code.