Problem overview
The function twoSum(nums: IntArray, target: Int): IntArray receives an array of integers and a target. It must return the indices of two numbers that add up to target, as an IntArray of two elements. If no such pair exists, it returns [-1, -1]. There is at most one solution, and the same index can't be used twice, although two equal values at different indices are fine.
In the example, nums = [2, 7, 11, 15] and target = 9. The numbers at indices 0 and 1 are 2 and 7, which add up to 9, so the result is [0, 1].
The statement allows O(n^2) time and O(1) extra space. That is the budget of a brute-force search over all pairs.
Approach: check every pair of indices
The answer is a pair of positions, so the candidates are all pairs of positions (i, j). Trying them all and testing nums[i] + nums[j] == target is guaranteed to find the solution if there is one.
To avoid wasted work, take only pairs with i < j. The pair (j, i) has the same sum as (i, j), so testing it would repeat the same check. Requiring j to start at i + 1 also stops an element from being paired with itself, which the problem forbids.
This is the simplest correct solution. Faster ones exist, such as remembering the numbers already seen in a hash map, but this lesson builds the nested-loop version first.
Step by step
- Loop over every possible first index. Use
for (i in nums.indices). The propertyindicesis the range of valid positions,0 until nums.size. - Loop over the second index. Inside it, use
for (j in i + 1 until nums.size). The range starts afteriand stops beforenums.size. For the lastithe range is empty, so the inner body doesn't run. - Test the pair and return. If
nums[i] + nums[j] == target, returnintArrayOf(i, j). Returning from inside the loops ends both of them, so the search stops at the first match. With at most one solution, it is the only match. - Handle the no-solution case. After the loops, return
intArrayOf(-1, -1). The line is reached only when every pair has been tried without success.
Take nums = [3, 4] and target = 6. The loops try only (0, 1), whose sum is 7. Nothing matches, so the function returns [-1, -1]. It doesn't pair the 3 with itself.
The solution in Kotlin
class Solution {
fun twoSum(nums: IntArray, target: Int): IntArray {
for (i in nums.indices) {
for (j in i + 1 until nums.size) {
if (nums[i] + nums[j] == target) {
return intArrayOf(i, j)
}
}
}
return intArrayOf(-1, -1)
}
}
The Kotlin details worth knowing:
IntArray. It is Kotlin's array of primitiveintvalues, created withintArrayOf(...)and read withnums[i]. It differs fromArray<Int>, which holds boxed objects, and fromList<Int>. The function signature usesIntArray, so the result has to be one too.- Operator precedence in ranges. In
i + 1 until nums.size, the arithmetici + 1is evaluated first, thenuntilbuilds the range. No parentheses are needed. - Return from inside a loop. A
returnleaves the whole function, not only the loop it is in. That is why nobreakis needed. - Printing and comparing arrays. Printing an
IntArraydirectly gives an object description such as[I@1b6d3586. UsecontentToString()to see[0, 1]. And==on two arrays compares references, so two arrays with the same contents are not equal:contentEqualscompares the elements. - Empty ranges are fine. If the start is greater than the last allowed value, the loop simply doesn't run, so no extra check for a short array is needed.
Intaddition wraps.2000000000 + 2000000000gives-294967296, not 4000000000. With those two numbers andtarget = -294967296, the function returns[0, 1]. The lesson's inputs stay far from this limit. For arbitrary values, you could add them asLong.
Complexity
Time: O(n^2). For n numbers, the pairs with i < j number n(n - 1) / 2. In the worst case, when there is no solution or it sits at the end, all of them are tested, and each test takes constant time.
Space: O(1). The function uses only the two loop variables and, at the end, one small result array whose size doesn't depend on n.
Edge cases and common mistakes
- Fewer than two numbers. An empty array or a single element has no pair. The loops find nothing and the function returns
[-1, -1]. - Equal values.
[3, 3]with target 6 returns[0, 1]. Two different positions that hold the same number are allowed. - Using the same element twice.
[3, 4]with target 6 returns[-1, -1]. Startingjatiwould wrongly report[0, 0]. - Returning values instead of indices. The answer for
[2, 7, 11, 15]is[0, 1], not[2, 7]. - Negative numbers. The comparison works without changes:
[-3, 4, 3, 90]with target 0 returns[0, 2]. - Forgetting the final return. A Kotlin function with a block body and a return type must return on every path. Without the last line the code doesn't compile.
- Returning a
List. The signature needs anIntArray, solistOf(i, j)is a type error. - Order of indices. The smaller index comes first. For
[7, 2]and target 9 the result is[0, 1].
Testing
nums = [2, 7, 11, 15],target = 9gives[0, 1].nums = [3, 3],target = 6gives[0, 1].nums = [3, 4],target = 6gives[-1, -1].nums = [-3, 4, 3, 90],target = 0gives[0, 2].nums = [],target = 5gives[-1, -1].