Problem overview
The function getFullNames(names: Array<String>) receives an array in which first names and last names alternate: a first name, then the matching last name, then the next first name, and so on. It returns a list of full names, each built from a first name and a last name with one space between them.
For ["John", "Doe", "Andy", "Smith", "Mary", "Johnson"] the result is ["John Doe", "Andy Smith", "Mary Johnson"]. The input has six strings and the output has three, one per pair.
Approach
The pairs start at the even indices 0, 2, 4, and so on. Index 0 holds a first name and index 1 its last name; index 2 holds the next first name and index 3 its last name. So a loop that visits only the even indices can build a full name at each stop from names[i] and names[i + 1].
The result needs a place to collect the names as they are built, and the order of the pairs in the input must carry over to the output. A mutable list that grows at the end does both.
Step by step
- Create the result list.
val answer = mutableListOf<String>()is an empty list that accepts additions. - Loop over the even indices.
for (i in 0 until names.size step 2)counts 0, 2, 4, ... and stops before the size. Each value ofiis the position of a first name, andi + 1holds the last name that goes with it. - Build one full name.
names[i] + " " + names[i + 1]joins the first name, a space and the last name into a single new string. - Save it.
answer.add(name)appends at the end, so the output keeps the input's order. - Return after the loop. The
return answergoes below the loop's closing brace. If it were inside, the function would return after the first pair.
The solution in Kotlin
class Solution {
fun getFullNames(names: Array<String>): List<String> {
val answer = mutableListOf<String>()
for (i in 0 until names.size step 2) {
val name = names[i] + " " + names[i + 1]
answer.add(name)
}
return answer
}
}
Kotlin details:
untilandstep.0 until names.sizeis a range that excludes its upper end, andstep 2makes it skip every other number. Both are infix functions, so they read left to right:(0 until names.size) step 2.- Read-only return type, mutable value. The function is declared to return
List<String>, which a caller can only read, butansweris aMutableList<String>inside. AMutableListis aList, so returning it is allowed. The list was declared withval, andvalonly stops reassigning the variable;addstill changes the list. - String concatenation.
+on strings builds a new string each time, so the original names aren't changed. A string template,"${names[i]} ${names[i + 1]}", produces the same text. Array<String>. The parameter is an array, andnames.sizegives its length. AListwould use the samesizeproperty.- Type inference.
val namegets its type,String, from the expression on the right, so it needs no annotation.
Complexity
Time: O(n), where n is the length of names. The loop runs n / 2 times, and each run joins two short strings and adds to the list. Treating the name length as a constant, the work per pair is constant.
Space: O(n) for the result, which holds n / 2 strings, each as long as a first name plus a last name.
Edge cases and common mistakes
- Empty array. The range
0 until 0is empty, so the loop doesn't run and the function returns an empty list. - Odd length. The statement gives pairs, so the length should be even. If it is odd, such as
["A", "B", "C"], the last pass readsnames[3], which doesn't exist, and the program throws anArrayIndexOutOfBoundsException. - Stepping by 1. A loop without
step 2would build names like"Doe Andy"from the wrong neighbours and produce too many entries. - Using
..for the range.0..names.sizereaches an index that is out of range. Useuntilfor the upper bound. - Missing space.
names[i] + names[i + 1]gives"JohnDoe". The space is part of the expected output. - Returning inside the loop. Only the first full name would come back.
Testing
["John", "Doe", "Andy", "Smith", "Mary", "Johnson"]gives["John Doe", "Andy Smith", "Mary Johnson"].["Ada", "Lovelace"]gives["Ada Lovelace"].[]gives[].