オットセイの経営日誌

データサイエンス系ベンチャーを経営してます。経営のこと、趣味のことつぶやきます。

LeetCode / Find the Difference

シンプルな問題ですが、dictionary使ったり、Counter使ったり、アスキーコード使ったり、ビット演算使ったりと、解法が多岐にわたる良問かも。

https://leetcode.com/problems/find-the-difference/

Given two strings s and t which consist of only lowercase letters.

String t is generated by random shuffling string s and then add one more letter at a random position.

Find the letter that was added in t.

Example:

Input:
s = "abcd"
t = "abcde"

Output:
e

Explanation:
'e' is the letter that was added.

文字列sに対して、ランダムに組み換えた上で新たな文字を追加した文字列tがあり、追加された文字を特定する問題。

解答・解説

解法1

私の解法です。collections.Counterを使う方法。

class Solution:
    def findTheDifference(self, s: str, t: str) -> str:
        count_s = collections.Counter(s)
        count_t = collections.Counter(t)
        for k in count_t:
            if count_t[k] != count_s[k]:
                return k

公式ドキュメントに記載の通り、カウンタオブジェクトは辞書のインタフェースを持ちますが、存在しない要素に対して KeyError を送出する代わりに 0 を返すという違いがあるので、if count_t[k] != count_s[k] とすれば、kがsに存在しない場合もcount_s[k] = 0が返り、if条件にひっかけることができます。

解法2

以下、Discussionから。 Counterを使わずdictionaryで解く方法。dic.get()でkeyがなくても処理できることをなかなか覚えられない。。

class Solution(object):
    def findTheDifference(self, s, t):
        dic = {}
        for ch in s:
            dic[ch] = dic.get(ch, 0) + 1
        for ch in t:
            if dic.get(ch, 0) == 0:
                return ch
            else:
                dic[ch] -= 1
解法3

アスキーコードを使って文字列を整数の和としてしまい、2つの文字列の差分をとって、最後に文字に戻す方法。

class Solution:
    def findTheDifference(self, s, t):
        diff = 0
        for i in range(len(s)):
            diff -= ord(s[i])
            diff += ord(t[i])
        diff += ord(t[-1])
        return chr(diff)
解法4

XOR(排他的論理和)を使う方法。

class Solution:
    def findTheDifference(self, s, t):
        code = 0
        for ch in s + t:
            code ^= ord(ch)
        return chr(code)

XORは和をとった2つの要素が同じであれば0になることを利用します。例えば、"aabbc"という文字列についてアスキーコードに変換してXORをとっていくと、以下のようになります。

for ch in "aabbc":
    code ^= ord(ch)
    print(ch, code)
# a 97
# a 0
# b 98
# b 0
# c 99

つまり、s, tの2つの文字列を結合してXORをとっていくと、文字列の差の分だけが残ることになります。