問題
英小文字だけでs をaaabcc は a3b1c2 に
- 縮めた
文字列が 元の sより短くなる ときだけ、 縮めた方を返します - 縮めた方が
元と 同じ 長さか、 元より 長くなる ときは、 元の sをそのまま返します sが空の 文字列なら、 空の 文字列を返します sの長さは 0 以上 10000 以下です
入力と出力の例
例 1
縮めると 9 文字が 6 文字に
入力
s = "aaaabbbcc"出力
"a4b3c2"例 2
縮めた a3b1c2 は 6 文字で、
入力
s = "aaabcc"出力
"aaabcc"例 3
続いた
入力
s = "zzzzzzzzzzzz"出力
"z12"面接での聞かれ方
面接では、
- 「aaabcc を a3b1c2 のように
縮める 関数を 書いてください」 - 「縮めても
短くならない ときは どうしますか?」と、 返す物の 決まりを あとから 足されます - 書き終えた
あとに 「文字列を 足していく 書き方の 計算量は?」と 聞かれる こともあります
数が 2 桁以上に
まず 考える手順
段 1
まずは、i のj をj がi から j のj - i です。
段 2
ひとi を j に+= で
段 3
そこで、s と
ここから解答です。先に自分で書いてから読むと、考え方が残ります。
解答
Python
Python
def compress_runs(s):
parts = []
i = 0
n = len(s)
while i < n:
j = i
while j < n:
if s[j] != s[i]:
break
j += 1
text = s[i] + str(j - i)
parts.append(text)
i = j
out = "".join(parts)
if len(out) < n:
return out
return sJavaScript
JavaScript
function compressRuns(s) {
const parts = [];
const n = s.length;
let i = 0;
while (i < n) {
let j = i;
while (j < n) {
if (s[j] !== s[i]) {
break;
}
j++;
}
const k = j - i;
parts.push(s[i] + k);
i = j;
}
const out = parts.join("");
if (out.length < n) {
return out;
}
return s;
}比べる
計算量
- 時間は O(n) です。
iとjはどちらも 前に しか進まないので、 どの 文字も 一定の 回数しか 読みません - 使う
記憶は O(n) です。 縮めた 結果は、 最悪の 場合に 元の 2 倍の 長さになります - 段 2 の、
文字列に 足していく 書き方は、 言語に よっては 時間が O(n²) まで落ちます
よく ある間違い
- 最後の
ひと 続きを 書き足し忘れる。 「前の 文字と 違ったら 書き足す」 書き方に すると、 文字列の 終わりに 来た ときの 分が 抜けます。 例 1 なら c2が付かずに a4b3を返します - 数を 1 桁と
決めつける。 長さを 文字 1 つで 書こうと すると、 例 3 の 12 が 正しく 書けません。 数は 文字列に してから つなぎます - 比べる
式を 「以下」にする。 同じ 長さの ときは 元を 返す決まりなので、 「より短い」で比べます
面接での 話し方の例
書き始める
「前から
読んで、 同じ 文字が 続く ひと 続きを 2 つの 位置で 見つけます。 見つける たびに 文字と 長さを 並びに ためて、 最後に 1 回だけつなぎます。 つないだ物が 元より 短い ときだけ それを 返し、 そうでなければ 元を 返します。 時間も 記憶も O(n) です。」
書き終えたら、
「例 2 の
"aaabcc"でたどります。 a が 3 つ、 b が 1 つ、 c が 2 つなので、 つなぐと a3b1c2 の 6 文字です。 元も 6 文字で 短くなっていないので、 元の aaabcc を 返します。」
