今回は paiza の「【文字列 3】p4!2@」の問題に挑戦!
leet表記について学んだ!
問題概要
〇 目的
入力文字列 S の中に “paiza” またはその Leet 表記 が含まれるかを判定する。
〇 Leet 表記のルール
“paiza” の中の文字を以下のように1回以上置換したものを Leet とみなす:
- a → 4 または a → @
- i → 1 または i → !
- z → 2
〇 判定条件
- もし
Sに “paiza” が含まれていれば →"paiza" - “paiza” は含まれないが、Leet 変換後に "paiza" が含まれるなら →
"leet" - どちらも含まれなければ →
"nothing"
○ 入力
文字列 S (長さ 1~100、使える文字は小文字アルファベット・数字・@・!)
〇 出力
"paiza", "leet", "nothing" のいずれか
〇 例
- 入力:
paizalove→ 出力:paiza - 入力:
p@1za→ 出力:leet - 入力:
leetp@1za→ 出力:leet - 入力:
hello→ 出力:nothing
入力例:
leetp@1za
出力例:
leet
❌NG例:
const rl = require('readline').createInterface({ input:process.stdin });
const lines = [];
rl.on ('line', (input) => lines.push(input));
rl.on('close', () => {
const S = lines[0].split('');
let leet = false;
for (let i = 0; i < S.length; i++) {
if (S[i] === '4') S[i] = 'a', leet = true;
if (S[i] === '@') S[i] = 'a', leet = true;
if (S[i] === '1') S[i] = 'i', leet = true;
if (S[i] === '!') S[i] = 'i', leet = true;
if (S[i] === '2') S[i] = 'z', leet = true;
if (i < 4) continue;
const temp = S.slice(i-4, i+1).join('');
if (temp === 'paiza') {
if (leet) {
console.log('leet')
} else {
console.log('paiza');
}
return;
}
}
console.log('nothing');
});
このコードは最初に配列 S を上書き('4' → 'a' など)し、 leet フラグを文字列全体で一度でも置換が発生したら true にしてしている。
その結果、元の文字列に素の "paiza" が含まれていても、その前に別の場所で leet 文字(4 や 1 など)を見つけてしまうと leet が true になり、素の "paiza" を見つけたときに leet を出力してしまう可能性がある。
✅OK例:
const rl = require('readline').createInterface({ input:process.stdin });
const lines = [];
rl.on ('line', (input) => lines.push(input));
rl.on('close', () => {
const orig = lines[0]; // 元の文字列を保存
// まず「素の paiza が含まれるか」を優先チェック
if (orig.includes('paiza')) {
console.log('paiza');
return;
}
// 元のに含まれなければ、Leet を通常文字に置換して検索
const S = orig.split('');
for (let i = 0; i < S.length; i++) {
if (S[i] === '4') S[i] = 'a';
if (S[i] === '@') S[i] = 'a';
if (S[i] === '1') S[i] = 'i';
if (S[i] === '!') S[i] = 'i';
if (S[i] === '2') S[i] = 'z';
if (i < 4) continue;
const temp = S.slice(i-4, i+1).join('');
if (temp === 'paiza') {
console.log('leet');
return;
}
}
console.log('nothing');
});
まず元の文字列に “paiza” が含まれているかを先にチェックし、含まれていなければ leet 置き換えしてからチェックする。
💡 .includes で部分文字列 "paiza" が含まれているか判定できる。
- paiza を含む:”xxpaizayy” →
paiza(優先) - Leet 表記のみ:”p@1za” →
leet(置き換え後に検出) - どちらも無い:”hello” →
nothing
それぞれ、出力したら return でプログラムを終了する。
✨OK例:
const rl = require('readline').createInterface({ input:process.stdin });
const lines = [];
rl.on('line', input => lines.push(input));
rl.on('close', () => {
const S = lines[0];
// まず置き換え前の paiza が含まれるか確認(優先)
if (S.includes('paiza')) {
console.log('paiza');
return;
}
// 全体を Leet->通常文字へ変換
let norm = '';
for (const ch of S) {
if (ch === '4' || ch === '@') norm += 'a';
else if (ch === '1' || ch === '!') norm += 'i';
else if (ch === '2') norm += 'z';
else norm += ch;
}
// 変換後に paiza が含まれるか調べる
if (norm.includes('paiza')) console.log('leet');
else console.log('nothing');
});
📝まとめ
🔹判定は2段階でやるのが鉄則
- まず「素の "paiza"」が入ってるか確認する
- それがなければ「Leet を普通の文字に戻して "paiza" を探す」
🔹NGパターン
- 最初から全部を Leet → 通常文字に変換してチェックすると、
"paiza" が入っていても誤って "leet" と判定してしまうことがある
🔹文字列検索の基本
-
S.includes("paiza")で部分文字列の有無を一発で判定できる
🔹置換の仕方
- Leet 記号を普通の文字に直す
- 4 or @ → a
- 1 or ! → i
- 2 → z
🔹考え方のコツ
- 「優先順位をつけて判定する」ことが大事
- 変換は後回し、まずそのままチェック!