まん中から 広げて 回文に なっている 部分文字列を 全部数える
文字列の
海外で定番の問題リスト 4 本には入っていません
問題
文字列 s をs の
- 中身が
同じでも、 sの中の 場所が 違えば 別々に 数えます。 たとえば "aa"の 1 文字目の"a"と 2 文字目の"a"は 2 つです - 1 文字だけの
部分文字列も 回文として数えます sの長さは 1 以上 1000 以下で、 英小文字だけです
入力と出力の例
例 1
1 文字の"oo" が 1 つ、"noon" が 1 つで 6 つです。
例 2
1 文字の"eve" と "level" で 7 つです。
例 3
同じ
面接での聞かれ方
面接では、
- 「文字列の
中に、 回文の 部分文字列は いく つありますか」 - 最初に
「同じ 中身でも 場所が 違えば 別に 数えますか?」 「1 文字も 数えますか?」と 確かめられるかを 見られます - 全部の
部分文字列を 作って 確かめる O(n³) の 書き方から、 O(n²) へ 下げられるかを 見られます
数え方の
ヒント
まだ開いていません
付箋は 4 枚。下の段ほど答えに近づきます
ヒント 2
ヒント 3
ヒント 4答えに近い
アルゴリズムのチートシートの「配列と文字列」に、
関わる学び
配列と
まず 考える手順
段 1
素直に
段 2
回文は、
段 3
まん中には 2 種類あります。
段 4
まん中は 2n - 1 個
解答
Python
Python
def grow(s, lo, hi):
found = 0
n = len(s)
while lo >= 0 and hi < n:
if s[lo] != s[hi]:
break
found += 1
lo -= 1
hi += 1
return found
def count_palindromes(s):
total = 0
for i in range(len(s)):
odd = grow(s, i, i)
even = grow(s, i, i + 1)
total += odd + even
return totalJavaScript
JavaScript
function grow(s, lo, hi) {
const n = s.length;
let found = 0;
while (lo >= 0 && hi < n) {
if (s[lo] !== s[hi]) {
break;
}
found++;
lo--;
hi++;
}
return found;
}
function countPalindromes(s) {
const n = s.length;
let total = 0;
for (let i = 0; i < n; i++) {
total += grow(s, i, i);
total += grow(s, i, i + 1);
}
return total;
}Go
Go
func grow(
s string, lo, hi int,
) int {
found := 0
for lo >= 0 && hi < len(s) {
if s[lo] != s[hi] {
break
}
found++
lo--
hi++
}
return found
}
func countPalindromes(
s string,
) int {
total := 0
for i := 0; i < len(s); i++ {
total += grow(s, i, i)
total += grow(s, i, i+1)
}
return total
}grow は、lo とhi を(i, i) は 1 回目で(i, i + 1) は、i + 1 は
計算量
- 時間は O(n²) です (n は
sの長さ)。 まん中が 2n - 1 個 あり、 それぞれ最大 n / 2 回広げます。 同じ 文字ばかりの "aaaa…"がいちばん遅い形です - 使う
記憶は O(1) です。 持つのは 指 2 本と 数だけです t[i][j](i 文字目から j 文字目が回文か ) の 表を 埋める 動的計画でも 時間は O(n²) ですが、 記憶が O(n²) になります
よく ある間違い
- 偶数の
長さを 数え忘れる。 まん中を 1 文字だけに すると、 "oo"や"noon"が数えられません。 例 1 で 4 を 返したら、 この 間違いです - 中身の
違う 回文だけを数える。 集合に 入れて 重なりを 消すと、 "aaa"で 3 (a、aa、 aaa) に なります。 場所が 違えば 別なので 6 が 正しい答えです - 回文で
なくなっても 広げ続ける。 左右が 違った 所で 止めずに 外側を 見ると、 外側の たまたま 同じ 文字を 回文として 数えてしまいます
解答を動かした版 Python 3.14.7Node.js 24.22.1Go 1.24.2確認日 2026年11月8日
面接での 話し方の例
書き始める
「全部の
部分文字列を 確かめると O(n³) です。 回文は まん中から 左右へ 同じ 文字が 続く 形なので、 まん中を 1 文字の 物と 2 文字の 間の 物の 2n - 1 個に 分け、 左右の 指を 外へ 広げられた 回数を 足します。 時間は O(n²)、 記憶は O(1) です。」
書き終えたら、
「例 1 の
noonでたどります。 1 文字の まん中は、 どれも 1 回広げた所で 止まるので 4 です。 2 文字の 間は、 n と o の 間と o と n の 間は 0、 o と o の 間は ooで 1 回、外の n と n も 同じなので noonで 2 回目です。合わせて 6 です。」