🪞
JavaScriptで解くLeetCode:Longest Palindromic Substring
このシリーズでは、プログラミング学習サイト LeetCode に掲載されている問題の中から良問を厳選し、JavaScript を使って解説します。
今回は、Arai60に収録されている「Longest Palindromic Substring(最長の回文部分文字列を探す)」の問題を解説します。
Palindromic は、回文ですね。しんぶんし:上から読んでも「しんぶんし」、下から読んでも「しんぶんし」。
この問題では、入力文字列の中で最も長い回文(前から読んでも後ろから読んでも同じ文字列)を返すことが求められます。
では、コードの各部分を詳しく解説していきます。
問題の要件
入力
- 文字列
s
(長さ1以上1000以下、英数字のみ)
出力
- 入力文字列の中で最も長い回文部分文字列
例
-
入力:
"babad"
出力:"bab"
または"aba"
-
入力:
"cbbd"
出力:"bb"
コードの解説
全体の構造
var longestPalindrome = function(s) {
if (s.length < 2) return s;
let start = 0;
let maxLength = 1;
function expandAroundCenter(left, right) { ... }
for (let i = 0; i < s.length; i++) { ... }
return s.substring(start, start + maxLength);
};
-
初期条件の処理
- 入力文字列の長さが2未満の場合、回文探索を行わず文字列をそのまま返します。
if (s.length < 2) return s;
-
変数の初期化
-
start
: 最長回文部分文字列の開始位置を保持。 -
maxLength
: 最長回文部分文字列の長さを保持。
let start = 0; let maxLength = 1;
-
-
補助関数
expandAroundCenter
- 回文の中心を左右に拡張するロジックを実装しています。
- 入力:
-
left
(中心の左側のインデックス) -
right
(中心の右側のインデックス)
-
- 処理内容:
- 左右の文字が一致している間、範囲を広げて回文の長さを更新。
function expandAroundCenter(left, right) { while (left >= 0 && right < s.length && s[left] === s[right]) { const currentLength = right - left + 1; if (currentLength > maxLength) { start = left; maxLength = currentLength; } left--; right++; } }
-
全文字を中心として探索
- 各文字を中心にして奇数長の回文を探索。
- 文字間を中心として偶数長の回文を探索。
for (let i = 0; i < s.length; i++) { expandAroundCenter(i, i); // 奇数長の回文 expandAroundCenter(i, i + 1); // 偶数長の回文 }
-
最終結果を返す
-
start
からstart + maxLength
の範囲を抜き出し、最長回文部分文字列を返します。
return s.substring(start, start + maxLength);
-
コードのポイント
-
回文の中心を拡張するアイデア
- 回文は「中心」を基準に左右対称である性質を持っています。この性質を利用して、すべての文字を中心として探索することで、最長回文を見つけます。
- 時間計算量は (O(n^2))、空間計算量は (O(1)) です。
-
奇数長と偶数長の回文を区別
- 回文の長さが奇数の場合、中心は1文字。
- 回文の長さが偶数の場合、中心は2文字間。
例を使った動作説明
"babad"
入力: -
初期状態
start = 0
maxLength = 1
-
探索開始
-
i = 0
: 奇数回文 →"b"
、偶数回文 → 空 -
i = 1
: 奇数回文 →"bab"
、偶数回文 → 空 -
i = 2
: 奇数回文 →"aba"
、偶数回文 → 空 -
i = 3
: 奇数回文 →"a"
、偶数回文 → 空 -
i = 4
: 奇数回文 →"d"
、偶数回文 → 空
-
-
結果
- 最長回文は
"bab"
または"aba"
。
- 最長回文は
応用と改良
-
時間効率を上げる方法
- 動的計画法(Dynamic Programming)を用いれば、時間計算量を (O(n^2)) に保ちながら空間計算量を減らす工夫が可能です。
-
文字列の長さが大きい場合
- (O(n)) の解法として「Manacher's Algorithm」を使用すると効率的です。
このコードはシンプルで理解しやすい一方、効率をさらに高める余地もあります。
まずは「回文の中心を拡張する」という考え方を実装してみてください。
では See you later, alligator!
Discussion