Problem overview
You get two strings, s and t. The string t is s with its letters shuffled and one extra letter inserted somewhere. findTheDifference must return that extra letter as a Char.
For s = "abcd" and t = "abcde" the answer is 'e', because t holds every letter of s plus an e. For s = "" and t = "y" the answer is 'y': with nothing to shuffle, the extra letter is the whole of t. Both strings use lowercase letters only, and t is always exactly one character longer than s.
Approach: compare how often each letter occurs
Shuffling doesn't change how many times each letter occurs, so the position of letters is useless here. What changes is the count: the added letter occurs one more time in t than in s, and every other letter occurs equally often in both.
That gives a direct plan. Take each character of t in turn, count it in s, count it in t, and stop at the first character whose two counts differ. The extra letter must be among the characters of t, so scanning t is guaranteed to reach it. Scanning s instead would fail whenever the extra letter doesn't appear in s at all.
The plan is brute force: every character of t triggers two full passes over a string. It is the simplest correct approach and a good first version. The later lessons on this problem replace the repeated counting with a stored count table and then with XOR.
Take s = "ab" and t = "bab". The first character of t is b. It occurs once in s and twice in t, so the counts differ and the function returns 'b' right away. This shows that the extra letter can be a copy of a letter s already has, so checking whether s contains it would not be enough. You have to compare counts.
Here is the first example in full, s = "abcd" and t = "abcde". For a the counts are 1 and 1, and the same holds for b, c and d, so the loop moves on each time. For e the count in s is 0 and in t is 1. That is the first mismatch, so the function returns 'e'. Because the loop returns on the first mismatch and exactly one letter can mismatch, the order of the characters in t doesn't matter.
Step by step
- Add a helper,
countChar(s: String, c: Char): Int, to theSolutionclass. The main method calls it twice per character, so it is worth naming. - Start a counter. A
var count = 0is the running tally. It is avarbecause it changes. - Loop over the string.
for (ch in s)walks through the characters ofsfrom left to right. - Test each character.
ch == casks whether this character is the one being counted. - Increment on a match.
count++adds one. - Return the tally after the loop.
- In
findTheDifference, loop overt. The extra letter is int, so every candidate comes from there. - Compare the counts. If
countChar(s, i) != countChar(t, i), this letter occurs more often int, which makes it the added one. - Return it immediately, and add a fallback return after the loop so that every path returns a
Char.
The solution in Kotlin
class Solution {
fun countChar(s: String, c: Char): Int {
var count = 0
for (ch in s) {
if (ch == c) {
count++
}
}
return count
}
fun findTheDifference(s: String, t: String): Char {
for (i in t) {
if (countChar(s, i) != countChar(t, i)) {
return i
}
}
return ' '
}
}
Kotlin details worth a look:
- A
Stringcan be looped over directly.for (i in t)gives oneCharper turn, so no index is needed. CharagainstString. A single character is written with single quotes,'e', and has typeChar. Double quotes make aString, which wouldn't match the declared return type.==on characters compares their values, which is whatch == cneeds.- The last
return ' 'is required. The compiler can't know that the loop always finds a mismatch. Without that line it reportsmissing return statement. For valid input the line never runs. count++andvar.countis anIntdeclared withvar, so it can be reassigned, and++adds one to it. Avalwould not allow that. The method's declared return type,Int, matches it.- Members call each other by name.
countCharsits in the same class, sofindTheDifferencecalls it without any prefix.
Complexity
Time: O(n²), where n is the length of t. Each countChar call walks a whole string, which costs O(n), and the loop makes two calls for each of up to n characters. With strings of at most 1000 letters that is a few million steps at worst, which is fine here but wasteful.
Space: O(1). The function keeps one counter and the loop variable. It never builds a table.
Edge cases and common mistakes
- Empty
s.countChar("", 'y')is 0 whilecountChar("y", 'y')is 1, so'y'is returned. - The extra letter repeats an existing one. With
s = "aab"andt = "baab", the count ofais 2 in both strings and the count ofbis 1 against 2. The function returns'b'. - Looping over
s. A letter that never appears inswould never be examined. - Using a membership test. Asking whether
scontains the letter fails as soon as the added letter is a duplicate. - Dropping the fallback return. The code doesn't compile without it.
Testing
s = "abcd",t = "abcde"gives'e'.s = "",t = "y"gives'y'.s = "aab",t = "baab"gives'b'.s = "ab",t = "bab"gives'b'.
