Problem overview
The method findTheDifference receives two strings, s and t. The string t is s shuffled, plus one extra lowercase letter at a random position. The method returns that letter. s may be empty, and t is exactly one character longer than s.
For s = "abcd" and t = "abcde" the answer is "e", and for s = "" and t = "y" it is "y". This lesson asks for O(n) time and O(1) extra space.
Approach: let equal letters cancel out
Counting letters with count() costs O(n²), and a dictionary of counts gets to O(n) time. Both work, but there is a shorter idea that needs only one integer.
Every character has a numeric code, which Python returns from ord(): ord('a') is 97 and ord('e') is 101. The XOR operator ^ combines two integers bit by bit, and it has three properties that matter here:
x ^ x == 0: a number XORed with itself disappears;x ^ 0 == x: XOR with 0 changes nothing;- the order does not matter, so
a ^ b ^ aequalsb.
Now XOR the codes of every letter of s and every letter of t into one number that starts at 0. Each letter of s has a matching letter in t, so the two codes cancel to 0 wherever they sit in the strings. Only the extra letter has no partner, so its code is all that remains. Converting it back with chr() gives the answer.
With s = "ab" and t = "aba", the codes are 97, 98 and 97, 98, 97. The two 97s from the matching pair cancel, as do the two 98s, and one 97 is left. chr(97) is "a", which is the extra letter.
Step by step
- Start an accumulator named
resultat 0. Becausex ^ 0 == x, 0 is the neutral starting value. - Loop over
swith the variablec. - XOR in each code.
ord(c)turns the letter into an integer, because^works on numbers, not on strings.^=updatesresultin place. - Loop over
tin the same way. - XOR in each code again. After this loop, every letter that appears in both strings has been XORed an even number of times in total and has cancelled. The extra letter was XORed one more time than it appears in
s, so it survives. - Convert back.
chr(result)turns the remaining code into a one-character string and returns it.
The solution in Python
class Solution:
def findTheDifference(self, s: str, t: str) -> str:
result = 0
for c in s:
result ^= ord(c)
for c in t:
result ^= ord(c)
return chr(result)
Python details worth knowing:
ordandchrare inverses.ord("e")is 101 andchr(101)is"e". Withoutord,result ^= cwould raise aTypeError, since an integer cannot be XORed with a string.^is XOR, not a power. Exponentiation in Python is**.- Python integers don't overflow. The codes of lowercase letters are between 97 and 122, and XOR of numbers below 128 stays below 128, so
chralways receives a valid code. - Order is irrelevant. The two loops could be swapped, or merged over both strings, and the result would be the same.
Complexity
Time: O(n). The loops perform one XOR per letter, n - 1 letters for s and n for t, and each XOR takes constant time.
Space: O(1). The only state is the integer result and the loop variable. Unlike the dictionary approach, nothing depends on the alphabet size at all.
Edge cases and common mistakes
- Empty
s. The first loop does nothing,resultis still 0, and the second loop sets it to the code of the single letter int. Fort = "y"the answer is"y". - The extra letter equals an existing one. With
s = "aab"andt = "abaa", threeacodes and onebare XORed fromtand twoacodes and onebfroms. Pairs cancel, and onearemains. XOR needs no special case for this. - Using
+instead of^. Adding the codes of both strings does not cancel them. A sum oftminus a sum ofswould work, but that is a different approach. - Forgetting
ordorchr. Withoutordthe XOR fails with aTypeError. Withoutchrthe method returns a number such as 101 instead of"e". - Relying on valid input. The cancellation works only because
tcontains exactly the letters ofsplus one. For other inputs the result is just the XOR of whatever is left.
Testing
s = "abcd",t = "abcde"gives"e".s = "",t = "y"gives"y".s = "ab",t = "aba"gives"a".s = "abcd",t = "dcbae"gives"e".
