Problem overview
The function longestCommonPrefix(s1: String, s2: String) returns the longest string that both inputs start with. A prefix is a beginning of a string, so the common prefix is the run of characters at the start that match in both.
The examples show the three kinds of result. For "hello" and "help" the first three characters match (h, e, l) and the fourth differs (l against p), so the answer is "hel". For "Andy" and "Mircea" the very first characters differ, so the answer is the empty string "". For "AlgoCademy" and "Algo" the shorter string is entirely a prefix of the longer one, so the answer is "Algo".
Approach
Compare the two strings position by position from the left. While the characters at the same index are equal, the prefix keeps growing. At the first index where they differ, the prefix ends: no later match can extend it, because a prefix has to be unbroken from the start. So the loop can stop at that point.
There is one more limit. The loop can't look at an index that one of the strings doesn't have. The prefix is at most as long as the shorter string, so the loop runs only up to the shorter length.
Step by step
- Find the shorter length.
val n = minOf(s1.length, s2.length)gives the number of positions that exist in both strings. In Kotlin,lengthis a property, so there are no parentheses. - Start with an empty prefix.
var commonPrefix = ""is avarbecause it grows during the loop. - Loop over the shared positions.
for (i in 0 until n)visits indices 0 ton - 1. Theuntilrange excludes its upper end, which is what indexing needs. - Stop at the first difference. If
s1[i] != s2[i], callbreakto leave the loop. Indexing a string with[i]gives aChar, so!=compares two characters. - Extend the prefix. Code after the
ifonly runs when the characters matched, socommonPrefix += s1[i]adds that character. Either string would do, since they hold the same character here. - Return the result. The
returnafter the loop covers both ways of leaving it: abreakat a mismatch, or the end of the range when the shorter string is a prefix of the longer one.
The solution in Kotlin
class Solution {
fun longestCommonPrefix(s1: String, s2: String): String {
val n = minOf(s1.length, s2.length)
var commonPrefix = ""
for (i in 0 until n) {
if (s1[i] != s2[i]) {
break
}
commonPrefix += s1[i]
}
return commonPrefix
}
}
Kotlin details:
valandvar.nnever changes, so it is aval.commonPrefixis reassigned in the loop, so it is avar.- Strings are immutable.
commonPrefix += s1[i]doesn't change the old string. It creates a new, longer string made of the old text plus theChar, and the variable now refers to it. String + Charworks. Adding aCharto aStringwith+gives aString. Writing+between twoCharvalues does not join them into a string, so keep the string on the left.- Comparison with
!=. OnCharvalues it compares the characters. On strings,==and!=compare contents, not references. break. It ends the innermost loop immediately, and execution continues at the line after the loop.
A shorter way to build the result
Instead of growing a string, the loop can remember how many characters matched and cut the answer once at the end. The lesson builds the prefix character by character because it shows the idea directly: each match adds one character, and the first mismatch stops the process. Whichever form you use, the loop condition and the break are what make the answer correct.
Complexity
Let m be the length of the shorter string.
Time: O(m) comparisons, one per matching position plus at most one failing comparison. Because += copies the growing string each time, the total copying can reach O(m²) for a long prefix. For short strings this doesn't matter. To keep it linear, use s1.substring(0, i) once at the end, or a StringBuilder.
Space: O(m) for the result, which can be as long as the shorter input. Beyond the result the loop uses a few variables.
Edge cases and common mistakes
- An empty string. If either input is empty,
nis 0, the loop doesn't run, and the function returns"". - Identical strings. Every position matches and the whole string comes back.
"same"and"same"give"same". - Using the longer length. Looping to
s1.lengthreads past the end of the shorter string. Indexing a Kotlin string out of range throws aStringIndexOutOfBoundsException, which is why the loop uses the minimum. - Forgetting
break. Without it, the loop only skips the mismatched position and carries on, so later matching characters are added after the gap. With"abxd"and"abyd"the result would be"abd"instead of"ab". A prefix can't have a gap, which is why the first mismatch must end the loop. - Case. Characters are compared exactly.
'A'and'a'are different, so"Algo"and"algo"have an empty common prefix. - Using
..instead ofuntil.0..nincludesn, which is one past the last valid index of the shorter string.
Testing
"hello","help"gives"hel"."Andy","Mircea"gives""."AlgoCademy","Algo"gives"Algo"."","x"gives""."abxd","abyd"gives"ab".