問題
英小文字だけでa と b をa のb とtrue、false を
- 文字を
足したり消したりは できません。 並べ替えるだけです - 同じ
文字が 何回出るかも、 ぴったり そろっている 必要があります aとbの長さは、 どちらも 0 以上 10000 以下です
入力と出力の例
例 1
入力
a = "below"
b = "elbow"出力
true例 2
使っている
入力
a = "aab"
b = "abb"出力
false例 3
長さが
入力
a = "note"
b = "notes"出力
false面接での聞かれ方
面接では、
- 「2 つの
単語が、 文字の 並べ替えで 同じに なるかを 判定してください」 - 書き終えた
あとに 「いまの 書き方の 計算量は?」 「並べ替えずに できますか?」と 続けて 聞かれます - 「大文字や
空白が 入ったら?」 「日本語なら?」と、 入力が 広がった ときの 話を 聞かれる こともあります
使う
まず 考える手順
段 1
まずはsorted(a) == sorted(b) で
段 2
並べ替えは、
段 3
辞書 (Python の dict、Map) に、a のb をb のfalse です。
ここから解答です。先に自分で書いてから読むと、考え方が残ります。
解答
Python
Python
def same_letters(a, b):
if len(a) != len(b):
return False
count = {}
for ch in a:
seen = count.get(ch, 0)
count[ch] = seen + 1
for ch in b:
have = count.get(ch, 0)
if have == 0:
return False
count[ch] = have - 1
return TrueJavaScript
JavaScript
function sameLetters(a, b) {
if (a.length !== b.length) {
return false;
}
const count = new Map();
for (const ch of a) {
const c = count.get(ch);
count.set(ch, (c ?? 0) + 1);
}
for (const ch of b) {
const c = count.get(ch);
if (!c) {
return false;
}
count.set(ch, c - 1);
}
return true;
}段 1 のsorted(a) == sorted(b) の 1 行です。
計算量
- 時間は O(n) です。
aとbを 1回ずつ 読み、 辞書を 調べるのも 書き換えるのも、 平均して 一定の 手間で済みます - 使う
記憶は、 文字の 種類の 数だけです。 英小文字なら 多くても 26 種類なので、 O(1) と 見なせます - 段 1 の
並べ替える 書き方は、 時間が O(n log n) で、 並べ替えた 写しの ために 記憶を O(n) 使います
よく ある間違い
- 文字の
種類だけを比べる。 集合 ( set) にして 比べると、 例 2 の aabとabbがどちらも a と b に なり、 trueと答えてしまいます。 回数まで比べます - 長さを
先に 比べない。 長さを 比べずに bだけ読んで 減らすと、 aに余った 文字が あっても trueを返します。 例 3 なら、 長さの 違いを 先に 見れば 迷いません - JavaScript で
文字列を そのまま 並べ替えようとする。 文字列には sortが無いので、 [...a]のように、.sort() .join("") いったん 並びに してから 並べ替えます
面接での 話し方の例
書き始める
「両方を
並べ替えて 比べれば O(n log n) で 解けます。 ただ、 知りたいのは 文字ごとの 回数だけなので、 辞書で 数えれば O(n) に なります。 先に 長さを 比べて、 a で 数を 足し、 b で 数を 引きます。 途中で 足りなくなれば false です。」
書き終えたら、
「例 2 の
aabとabbでたどります。 長さは どちらも 3 です。 a から 数えると a が 2 回、 b が 1 回です。 b を 読むと、 a で 1 回減らし、 b で 1 回減らし、 次の b で 残りが 0 なので、 そこで false を 返します。」
