Problem overview
The method twoSum receives an array of numbers, nums, and a target. It must return the indices of two entries that add up to target, as an array [i, j]. There is at most one solution, and the same index can't be used twice. When no pair works, the method returns [-1, -1].
For nums = [2, 7, 11, 15] and target = 9, the values at indices 0 and 1 are 2 and 7, which add up to 9. The answer is [0, 1]. Note that the result holds positions in the array, not the values.
Approach: check every pair of indices
This lesson asks for O(n^2) time and O(1) extra space, which is the brute-force budget. The idea is to try each pair of positions, once, and stop at the first pair whose values add up to target. Faster solutions exist, such as remembering the values already seen so each number needs one lookup instead of a scan, but those come later. This one needs nothing but two loops.
To visit each pair once, the outer index i takes every position, and the inner index j takes only the positions after i. A pair (i, j) and the same pair as (j, i) are then not tested twice, and j can never equal i, so an element is never paired with itself.
Step by step
- Loop over the first index.
istarts at 0 and runs whilei < nums.length. Every position can be the first element of the pair. - Loop over the second index. Inside it,
jstarts ati + 1and runs whilej < nums.length. Starting right afteriavoids repeats and avoids using one index twice. - Test the pair. If
nums[i] + nums[j] === target, return[i, j]. Areturninside the loops ends the whole method, so the search stops at the first match. - Return
[-1, -1]after the loops. This line is reached only if every pair was tried and none matched.
The solution in TypeScript
class Solution {
twoSum(nums: number[], target: number): number[] {
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];
}
}
}
return [-1, -1];
}
}
Some details worth knowing:
- The outer loop could stop one step earlier. When
iis the last index, the inner loop has nothing to do. Running it anyway costs nothing noticeable, and the code stays simple. - The return type is
number[]. The array literal[i, j]is built at the moment of thereturn, so each call gets a new array. - Use
===. It compares without converting types. The annotations promise thatnumsholds numbers, but they are erased when the code is compiled, so nothing checks that at run time. If a string such as"3"got into the array,+would join text instead of adding. - Out-of-range reads don't crash. Reading past the end of an array in TypeScript gives
undefined. The loop bounds keep both indexes inside the array, so this doesn't come up here.
Complexity
Time: O(n^2). In the worst case, when no pair matches or the match is the last pair, the inner body runs for every pair of positions: (n - 1) + (n - 2) + ... + 1 = n(n - 1) / 2 times. That is quadratic in n. When the answer comes early, the method returns early, but the worst case sets the bound.
Space: O(1) extra. Apart from the result array of two elements, only the indexes i and j are stored.
Edge cases and common mistakes
- Empty array or one element. No pair exists, so the loops finish without a match and the method returns
[-1, -1]. - Using one index twice. For
nums = [3, 4]andtarget = 6the answer must be[-1, -1]. Ifjstarted ati, the method would pair the 3 with itself and return[0, 0]. - Equal values. For
nums = [3, 3]andtarget = 6the answer is[0, 1]. Two entries with the same value are still two different indices. - Returning values instead of indices. For
[2, 7, 11, 15]the method returns[0, 1], not[2, 7]. - Forgetting the fallback. Without the final
return [-1, -1], a miss ends the method without returning anything, so the caller receivesundefinedinstead of an array, and code that readsresult[0]then crashes. - Negative numbers. They need no special handling. For
[-3, 4, 3, 90]andtarget = 0the pair is[0, 2].
Testing
nums = [2, 7, 11, 15],target = 9gives[0, 1].nums = [3, 2, 4],target = 6gives[1, 2].nums = [3, 3],target = 6gives[0, 1].nums = [3, 4],target = 6gives[-1, -1].nums = [],target = 5gives[-1, -1].