ツーポインタで 回文を判定する
英字と
海外で定番の問題リスト 4 本のうち 4 本に入っています (Blind 75、NeetCode 150、Grind 75、LeetCode Top Interview 150)
問題
文字列 s をs のtrue、false を
- 英字の
大文字と 小文字は 区別しません。 Aとaは同じ 文字と 見なします - 空白や
記号など、 英字と 数字の ほかの 文字は 読み飛ばします - 英字と
数字が 1 つも 無い ときは trueを返します sの長さは 0 以上 10000 以下で、 ASCII の 文字 (半角の 英字、 数字、 空白、 記号) だけで できています
入力と出力の例
例 1
英字だけを
例 2
1a2 を
例 3
英字も
面接での聞かれ方
面接では、
- 「文字列が
回文か どうかを 判定してください。 記号は 無視して、 大文字小文字も 区別しません」 - 書き終えた
あとに 「余分な 記憶を 使わずに 書けますか?」と 続けて 聞かれます - 「英数字が 1 つも
無い ときは?」と、 端の 場合を 聞かれる こともあります
どの
ヒント
まだ開いていません
付箋は 3 枚。下の段ほど答えに近づきます
ヒント 2
ヒント 3答えに近い
アルゴリズムのチートシートの「配列と文字列」に、
関わる学び
配列と
まず 考える手順
段 1
まずは
段 2
写しを
段 3
指がtrue を
解答
Python
Python
def is_palindrome(s):
def ok(ch):
if not ch.isascii():
return False
return ch.isalnum()
def low(k):
return s[k].lower()
i = 0
j = len(s) - 1
while i < j:
if not ok(s[i]):
i += 1
elif not ok(s[j]):
j -= 1
elif low(i) != low(j):
return False
else:
i += 1
j -= 1
return TrueJavaScript
JavaScript
function isPalindrome(s) {
const re = /[A-Za-z0-9]/;
const ok = (c) => re.test(c);
const low = (k) => {
return s[k].toLowerCase();
};
let i = 0;
let j = s.length - 1;
while (i < j) {
if (!ok(s[i])) {
i++;
continue;
}
if (!ok(s[j])) {
j--;
continue;
}
if (low(i) !== low(j)) {
return false;
}
i++;
j--;
}
return true;
}Go
Go
func isPalindrome(
s string,
) bool {
ok := func(c byte) bool {
switch {
case 'a' <= c && c <= 'z':
case 'A' <= c && c <= 'Z':
case '0' <= c && c <= '9':
default:
return false
}
return true
}
low := func(k int) byte {
c := s[k]
if 'A' <= c && c <= 'Z' {
c += 'a' - 'A'
}
return c
}
i, j := 0, len(s)-1
for i < j {
if !ok(s[i]) {
i++
continue
}
if !ok(s[j]) {
j--
continue
}
if low(i) != low(j) {
return false
}
i++
j--
}
return true
}英字とtrue にi < j がtrue を
計算量
- 時間は O(n) です。
どの 繰り返しでも、 2 つの 指の どちらかが 必ず 1 つ以上寄るので、 合わせて n 回ほどで 終わります - 使う
記憶は O(1) です。 持つのは 2 つの 位置だけで、 写しの 文字列を 作りません - 段 1 の、
写しを 作って 逆と 比べる 書き方は、 時間は O(n) で 同じですが、 記憶を O(n) 使います
よく ある間違い
- 大文字と
小文字を そろえずに比べる。 例 1 の Tとtを別の 文字と 見て、 falseを返してしまいます。 比べる 直前に 両方を 小文字にします - 読み飛ばすときに
両方の 指を進める。 片方だけが 記号を 指しているのに 両方を 進めると、 比べるはずの 文字を 飛ばしてしまいます。 進めるのは 記号を 指している 指だけです - Python の
isalnumだけで英数字を 判定する。 isalnumは ASCII のほかの 文字、 たとえば 全角の 数字にも Trueを返します。 この 問題は ASCII の 範囲だけを 見るので、 isasciiと組み合わせます
解答を動かした版 Python 3.12.14Node.js 22.23.4Go 1.24.2確認日 2026年10月24日
面接での 話し方の例
書き始める
「英数字だけを
小文字で 取り出して 逆と 比べれば 解けますが、 写しの ために 記憶を O(n) 使います。 両端に 指を 置いて、 英数字でない 文字は その指だけ 進め、 英数字どうしなら 小文字に して 比べながら寄せていけば、 記憶は O(1) で 済みます。 時間は どちらも O(n) です。」
書き終えたら、
「例 2 の
"1-a-2"でたどります。 左の 指は 1、 右の 指は 2 を 指していて、 どちらも 英数字です。 小文字に しても 1 と 2 で 違うので、 そこで false を 返します。」