LoginSignup
2
1

More than 5 years have passed since last update.

アナグラムを判定する

Posted at

 問題を確認する

二つの文字がアナグラムかどうかを判定する

思考工程

例えば
listen
silent
はアナグラムです。
文字列の長さが同じかどうかを判定して最初に思い浮かぶのはlistenの最初の文字lをsilentに存在するかどうか判定して、iがsilentにあるかどうか判定して。。。全部の文字がsilentに存在すればアナグラムとなります。
これだとO(n^2)となりもう計算効率が悪くなります

改善

アナグラムとは本質的には同じ文字が同じ文字数あればいいので、各文字数をカウントして両者の文字数のカウントが同じになれば良い。
例えば
listen は l => 1, i => 1, s => 1, t => 1, e => 1, n => 1

silent は s => 1, i => 1, l => 1, e => 1, n => 1, t => 1

となりアナグラムだと判定できます。
listen と strike はn の数が違うのでアナグラムとはならないです。
ここまで来るとアナグラムはこの方法で解けそうです。

さて計算量はどうなるでしょうか? 文字数のカウントに必要な計算量が O(N + N)。そこから各文字数のカウントを確認する計算量がO(N) となります。
となって全体ではO(N)となります。最初の計算より効率が良さそうです。
じゃあメモリの使用量はどうなるかというと二つのハッシュマップを用意しないといけないためO(N + N) => O(N) となります。

実装

const isAnagram = (str1, str2) => {
    if(str1.length === str2.length) {
        const {str1Count, str2Count} = countLetter(str1, str2)
        return equalObj(str1Count, str2Count)
    } else {
        return false
    }
}
const equalObj = (obj, obj2) => {
    for(const key in obj) {
        if(obj[key] !== obj2[key]) {
            return false 
        }
    }

    return true
}
const countLetter = (str1, str2) => {
    function count(l, obj) {
        if(obj[l] == null) {
            obj[l] = 1
        } else {
            obj[l] += 1
        }
    }
    let str1Count = {}
    let str2Count = {}

    for(let i = 0; i < str1.length; i++) {
        const s1 = str1[i]
        count(str1[i], str1Count)
        count(str2[i], str2Count)
    }

    return {str1Count, str2Count}
}
isAnagram("listen", "strike"))

となりアナグラムの問題を解くことができます

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1