Problem overview
The method findTheDifference receives two strings. The string t is a shuffle of s with one extra lowercase letter inserted somewhere, and the method returns that extra letter. The string s can be empty, and t is always exactly one character longer than s.
For s = "abcd" and t = "abcde" the answer is "e". For s = "" and t = "y" the answer is "y". This lesson asks for O(n) time, where n is the length of t.
Approach: count s once, then use the counts up
A simple solution counts every letter of t inside both strings with count(). Each call reads a whole string, so the total is O(n²). The waste is that the same counts are recomputed again and again.
The faster idea computes the counts of s once and stores them in a dictionary that maps each letter to how many times it occurs in s. Then the method walks through t and treats the dictionary as a supply of letters. Each letter of t uses up one copy. Every letter that came from s finds a copy waiting. The extra letter is the one that finds none: either it never appeared in s, or all its copies were already used by earlier occurrences in t.
Take s = "ab" and t = "aba". The dictionary starts as {'a': 1, 'b': 1}. The first a uses the only a, leaving 0. The b uses the only b. The second a finds a count of 0, so it is the extra letter.
Walking through s once and t once, with average O(1) dictionary operations, gives O(n) time.
Step by step
- Create an empty dictionary named
counter. It will hold the number of occurrences of each letter ofs. - Loop over
swith the variablec, to visit every letter once. - Increment the count. A letter seen for the first time has no entry yet, so the code reads the current count with a default of 0 and adds one.
- Loop over
twith a second loop, again usingc. - Check for a missing copy. If the dictionary has no copy of
cleft, either because the letter is missing or because its count is 0, then this letter has no partner ins. - Return it. That letter is the answer, so the method returns immediately.
- Use up a copy. If the check did not fire, the letter has a partner, so its count goes down by one. Only letters that are in the dictionary reach this line.
- Add a fallback return after the second loop. With valid input the method always returns inside the loop, but the fallback keeps every path returning a string.
The solution in Python
class Solution:
def findTheDifference(self, s: str, t: str) -> str:
counter = {}
for c in s:
counter[c] = counter.get(c, 0) + 1
for c in t:
if counter.get(c, 0) == 0:
return c
counter[c] -= 1
return ' '
Python details worth knowing:
dict.get(key, default).counter.get(c, 0)returns the stored count, or 0 whencis not a key. Plaincounter[c]would raise aKeyErrorfor a missing key, so the first loop needsgetto start counting a new letter.- The same check covers two cases. A letter that is not in the dictionary and a letter whose count has dropped to 0 both give 0 from
get, so one comparison handles both. - Why
counter[c] -= 1is safe. It runs only after the check has shown the count is not 0, which meanscis a key with a positive count. It never raises aKeyError, and the count never goes below 0. - Dictionary size. Keys are lowercase letters, so the dictionary holds at most 26 entries.
Complexity
Time: O(n). The first loop runs n - 1 times and the second at most n times. Each dictionary read or write takes O(1) on average, so the total is linear.
Space: O(1). The dictionary can hold only the 26 lowercase letters, however long the strings are.
Edge cases and common mistakes
- Empty
s. The dictionary stays empty, the first letter oftgets 0 fromget, and it is returned. Fort = "y"the result is"y". - The extra letter duplicates an existing one. The extra
aint = "aba"is caught by the count reaching 0, not by the letter being absent. A solution that only tests membership misses it. - The extra letter is not the last one.
s = "abcd"andt = "abecd"returns"e"from the middle of the loop. The method returns at the first letter with no copy left, which is right because exactly one letter is extra. - Indexing instead of
get. Writingcounter[c] + 1in the first loop raises aKeyErroron the first letter.
Testing
s = "abcd",t = "abcde"gives"e".s = "",t = "y"gives"y".s = "ab",t = "aba"gives"a".s = "abcd",t = "dcbae"gives"e".
