問題
文字列 s をs の
- いちばん長い
回文が 同じ 長さで 複数ある ときは、 いちばん左から 始まる ものを返します - 1 文字だけの
部分も 回文です。 なので、 答えは 必ず 1 文字以上あります sの長さは 1 以上 1000 以下で、 英小文字と 数字だけで できています
入力と出力の例
例 1
入力
s = "levelup"出力
"level"例 2
"aba" と "cdc" は"aba" を
入力
s = "xabacdcy"出力
"aba"例 3
長さが
入力
s = "zxyyxq"出力
"xyyx"面接での聞かれ方
面接では、
- 最初に
「部分を 全部作って、 回文か 確かめます」と 言うと、 「長さ 1000 で 間に 合いますか?」と 聞かれます - 書き終えた
あとに 「長さが 偶数の 回文も 見つかりますか?」と、 まん中の 取り方を 確かめられます - 「表 (動的計画法) で
書くのと 比べて、 記憶は どう 違いますか?」と、 別の 書き方との 違いを 聞かれる こともあります
始める
アルゴリズムのチートシートの「配列と文字列」に、この型の要点を表とコードでまとめています。
まず 考える手順
段 1
まずは
段 2
回文は、
段 3
まん中は 2 種類あります。i と i)、i と i + 1) です。"xyyx" のような
段 4
同じ
解答
Python
Python
def longest_palindrome(
s
):
start = 0
size = 1
for c in range(len(s)):
for d in (0, 1):
lo, hi = grow(
s, c, c + d
)
if hi - lo > size:
start = lo
size = hi - lo
return s[start:start + size]
def grow(s, lo, hi):
n = len(s)
while 0 <= lo and hi < n:
if s[lo] != s[hi]:
break
lo -= 1
hi += 1
return lo + 1, hiJavaScript
JavaScript
function longestPalindrome(
s
) {
let start = 0;
let size = 1;
const n = s.length;
for (let c = 0; c < n; c++) {
for (const d of [0, 1]) {
const [lo, hi] = grow(
s, c, c + d
);
if (hi - lo > size) {
start = lo;
size = hi - lo;
}
}
}
return s.slice(
start, start + size
);
}
function grow(s, lo, hi) {
const n = s.length;
while (lo >= 0 && hi < n) {
if (s[lo] !== s[hi]) {
break;
}
lo--;
hi++;
}
return [lo + 1, hi];
}Go
Go
func longestPalindrome(
s string,
) string {
start, size := 0, 1
for c := 0; c < len(s); c++ {
for d := 0; d <= 1; d++ {
lo, hi := grow(s, c, c+d)
if hi-lo > size {
start, size = lo, hi-lo
}
}
}
return s[start : start+size]
}
func grow(
s string, lo, hi int,
) (int, int) {
for lo >= 0 && hi < len(s) {
if s[lo] != s[hi] {
break
}
lo--
hi++
}
return lo + 1, hi
}grow は、
計算量
- 時間は O(n²) です。
まん中が 2n - 1 か 所あり、 それぞれ 広げるのに 最大 O(n) かかります - 使う
記憶は O(1) です。 指と、 候補の 始まりと 長さだけを 持ちます (返す文字列の 分は 除きます) - 表を
使う 動的計画法でも 時間は O(n²) ですが、 「i から j までが 回文か」の 表に O(n²) の 記憶を 使います。 まん中から 広げる 書き方は、 記憶を O(1) に 抑えられます
よく ある間違い
- まん中を 1 文字の
場合しか 試さない。 長さが 奇数の 回文しか 見つからず、 例 3 の "zxyyxq"から"xyyx"が取れません。 2 文字の 間の まん中も試します - 候補を
入れ替える 条件を 「長さ以上」にする。 同じ 長さの 回文が 後から 見つかる たびに 入れ替わり、 いちばん右の ものが 残ります。 例 2 で "cdc"を返してしまいます - 広げ終えた
あとの 位置を そのまま使う。 ループを 抜けた 時点の 指は、 合わなかった 文字か 並びの 外を 指しています。 回文は 左の 指の 1 つ右から、 右の 指の 1 つ左までです
解答を動かした版 Python 3.12.14Node.js 22.23.4Go 1.24.6確認日 2026年10月30日
面接での 話し方の例
書き始める
「部分を
全部作って 確かめると O(n³) です。 回文は まん中から 左右に 同じ 文字が 続くので、 まん中を 1 文字の 場合と 2 文字の 間の 場合の 両方で 試し、 左右に 広げます。 まん中は 2n - 1 か所で、 それぞれ O(n) なので 時間は O(n²)、 記憶は O(1) です。 同じ 長さなら左を 返すので、 長い ときだけ 入れ替えます。」
書き終えたら、
「例 2 の
"xabacdcy"をたどります。 bをまん中に すると、 両側が aとaで"aba"、その外は xとcで止まり、 3 文字が 候補に なります。 dをまん中に すると "cdc"も 3 文字ですが、候補より 長くは ないので 入れ替えません。 答えは "aba"です。」
