問題
英小文字のstrs を
- 返す順は
次の とおりに 決めます。 組の 中の 語は strsに出てきた順に 並べます。 組どうしは、 その組の 語が strsに初めて 出てきた順に並べます - 同じ
語が 2 回 あれば、 2 つとも 同じ 組に 入れます。 空の 語 ""も 1 つの語として扱います strsの長さは 1 以上 10000 以下、 語の 長さは 0 以上 100 以下で、 使う 文字は aからzだけです
入力と出力の例
例 1
入力
strs = ["stop", "pots", "melon",
"lemon", "tops"]出力
[["stop", "pots", "tops"],
["melon", "lemon"]]例 2
使う
入力
strs = ["aab", "abb", "bab",
"baa"]出力
[["aab", "baa"], ["abb", "bab"]]例 3
空の
入力
strs = ["", "b", ""]出力
[["", ""], ["b"]]面接での聞かれ方
面接では、
- 「文字を
入れ替えると 同じに なる 単語どうしを グループに してください」 - 「2 つの
語が 同じ 組かを、 どうやって 調べますか?」と、 比べ方を 先に 聞かれます - 書き終えた
あとに 「1 語の 長さが 長い とき、 もっと 速く できますか?」と、 鍵の 作り方を 詰められます - 「大文字や
記号が 混ざったら?」と、 文字の 種類を 広げた 場合を 聞かれる こともあります
返す順を
アルゴリズムのチートシートの「ハッシュマップ」に、この型の要点を表とコードでまとめています。
まず 考える手順
段 1
まずは
段 2
同じ組のstop も pots も opst です。
段 3
並べ替えたa から z の 26 種類だけなので、
段 4
返す順をdict と JavaScript の Map はmap は
解答
Python
Python
def group_anagrams(strs):
groups = {}
for s in strs:
count = [0] * 26
for ch in s:
i = ord(ch) - 97
count[i] += 1
key = tuple(count)
if key not in groups:
groups[key] = []
groups[key].append(s)
return list(groups.values())JavaScript
JavaScript
function groupAnagrams(strs) {
const groups = new Map();
for (const s of strs) {
const count = Array(26)
.fill(0);
for (const ch of s) {
const code =
ch.charCodeAt(0);
count[code - 97]++;
}
const key = count.join(",");
if (!groups.has(key)) {
groups.set(key, []);
}
groups.get(key).push(s);
}
return [...groups.values()];
}Go
Go
func groupAnagrams(
strs []string,
) [][]string {
index := map[[26]int]int{}
out := [][]string{}
for _, s := range strs {
var key [26]int
for _, ch := range s {
key[ch-'a']++
}
i, ok := index[key]
if !ok {
i = len(out)
index[key] = i
out = append(out, nil)
}
out[i] = append(out[i], s)
}
return out
}97 は a のcount.join(",") と1 と 11 の
計算量
- 時間は O(n k) です。
n は 語の 数、 k は 語の 長さの いちばん 大きい値です。 語ごとに 文字を 1 回なめて 数え、 26 個の 数から 鍵を 作り、 辞書を調べます - 使う
記憶は O(n k) です。 全部の 語を 組に 入れて返し、 鍵も 語の 数だけ覚えます - 段 2 の
並べ替えた 名札を 使う 書き方は、 時間が O(n k log k) です。 語が 短ければ 差は 小さいので、 面接では どちらでも 通りますが、 違いを 言えると 強みになります
よく ある間違い
- 鍵に Python の
リストを使う。 リストは 中身を 変えられるので 辞書の 鍵に なれず、 エラーに なります。 tuple(count)に直します。 JavaScript で 並びを そのまま Mapの鍵に すると、 中身が 同じでも 別の 物として 扱われ、 組が まとまりません - 文字の
種類だけで比べる。 集合で 比べると、 例 2 の aabとabbが同じ組に なってしまいます。 文字ごとの 数まで比べます - 数を
つなぐ ときに 区切りを 入れない。 aが 1 個でbが 11 個の語と、 aが 11 個でbが 1 個の語が、 同じ 鍵に なることがあります - Go で
mapを回して 組を返す。 mapを回す順は 毎回変わるので、 組の 順が 決まりません。 組の 並びを 別に持ちます
解答を動かした版 Python 3.12.14Node.js 22.23.4Go 1.24.6確認日 2026年10月30日
面接での 話し方の例
書き始める
「組どうしを
比べると 組の 数だけ 手間が かかるので、 同じ組の 語に 共通の 鍵を 作って 辞書に 集めます。 文字を 並べ替えた物でも 鍵に なりますが、 文字は 26 種類だけなので、 文字ごとの 数を 数えた 並びを 鍵に すれば、 1 語を O(k) で 処理できます。 全体は O(n k) です。 返す順は、 初めて 出た鍵で 組を 作り、 あとは 後ろに 足していく ことで 保ちます。」
書き終えたら、
「例 2 を
たどります。 aabは a が 2 個、b が 1 個なので 新しい 組を 作ります。 abbは a が 1 個、b が 2 個で 鍵が 違うので、 2 つ目の 組です。 babは 2 つ目の組へ、 baaは 1 つ目の組へ 足します。 だから [["aab", "baa"], ["abb", "bab"]]です。」
