今回は paiza の「【条件判定 3】過剰コンプライアンス」の問題に挑戦!
padStart() は使ったことがあったけど、調べてみたら padEnd() も存在すると新たに知った!
問題概要
- 放送禁止単語
Sが与えられる。
-
N個の単語V1 … Vnを検閲するルール:-
ViがSと完全一致 →"banned"を出力 -
ViがSと同じ文字数で、かつ- 前半が一致 または 後半が一致
- その一致部分をすべて
"x"に置き換えて出力する
- それ以外 → そのまま出力
-
- ただし
Sの長さが奇数の場合は中央の文字を両方に含めて分割する点に注意。
例)
S = "paiza" (長さ 5 → 奇数)
- 前半 =
"pai"(中央iを含む) - 後半 =
"iza"(中央iを含む)
入力例:
5
paiza
paaaa
paiza
paisa
zaiza
ab
出力例:
paaaa
banned
xxxsa
zaxxx
ab
✅OK例:
const rl = require('readline').createInterface({ input:process.stdin });
const lines = [];
// 標準入力を1行ずつ読み込む
rl.on('line', (input) => lines.push(input));
rl.on('close', () => {
const N = Number(lines[0]); // 単語の個数
const S = lines[1]; // 放送禁止単語
const V = lines.slice(2); // 検閲対象の単語リスト
// 禁止単語の長さが奇数かどうかを判定
let odd = false;
if (S.length % 2 !== 0) odd = true;
// インデックス
const center = Math.ceil(S.length / 2) // 中央の位置を計算(ceilで切り上げ)
const firstHalfEnd = center; // 前半の終端インデックス
const secondHalfStart = !odd ? center : center-1; // 後半の開始インデックス(奇数なら中央を重複させるため -1)
// 禁止単語の前半と後半を切り出して保持
const firstS = S.slice(0, firstHalfEnd);
const secondS = S.slice(secondHalfStart);
// 各検閲対象の単語を処理
for (const word of V) {
// 長さが違う場合は検閲対象外、そのまま出力
if (S.length !== word.length) {
console.log(word);
continue;
}
// 完全一致した場合は "banned" を出力
if (word === S) {
console.log('banned');
continue;
}
// 単語を前半・後半に分割
const firstHalf = word.slice(0, firstHalfEnd);
const secondHalf = word.slice(secondHalfStart);
// 前半が禁止単語と一致した場合
if (firstHalf === firstS) {
if (odd) {
// 奇数の場合 → 中央文字がかぶるので後半の先頭を削って残す
console.log(secondHalf.slice(1).padStart(word.length, 'x'));
} else {
// 偶数の場合 → 後半だけ残して前をすべて x にする
console.log(secondHalf.padStart(word.length, 'x'));
}
}
// 後半が禁止単語と一致した場合
else if (secondHalf === secondS) {
if (odd) {
// 奇数の場合 → 中央文字がかぶるので前半の末尾を削って残す
console.log(firstHalf.slice(0, firstHalf.length-1).padEnd(word.length, 'x'));
} else {
// 偶数の場合 → 前半だけ残して後ろをすべて x にする
console.log(firstHalf.padEnd(word.length, 'x'));
}
}
// 前半・後半どちらも一致しない場合はそのまま出力
else {
console.log(word);
}
}
});
コードの流れ(全体)
- 入力の受け取り
- 1行目: 単語の個数
N - 2行目: 放送禁止単語
S - 3行目以降: 検閲対象の単語リスト
V
- 1行目: 単語の個数
- 放送禁止単語 S の前半・後半を準備
-
Sの長さが奇数なら中央の文字は前半と後半の両方に含めるように処理 - そのためのインデックス
firstHalfEndとsecondHalfStartを計算 -
Sの「前半」と「後半」の基準を切り出して保持
-
- 検閲処理(単語ごとにチェック)
- 長さが違う → そのまま出力
- 完全一致 →
"banned"出力 - 前半一致 → 後半部分を残して他を
"x"に置き換え - 後半一致 → 前半部分を残して他を
"x"に置き換え - どちらも一致しない → そのまま出力
- 結果を出力
🔍各部分の説明
🔹入力処理
const N = Number(lines[0]);
const S = lines[1];
const V = lines.slice(2);
-
N: 単語の数 -
S: 放送禁止単語 -
V: 検閲対象の単語配列(長さ N の配列)
🔹前半・後半の基準を作る
const odd = S.length % 2 !== 0;
const center = Math.ceil(S.length / 2)
const firstHalfEnd = center;
const secondHalfStart = !odd ? center : center-1;
const firstS = S.slice(0, firstHalfEnd);
const secondS = S.slice(secondHalfStart);
-
odd: 禁止単語の長さが奇数かどうか -
center: 中央位置(半分の長さ) -
firstHalfEnd: 前半の切り出し終点 -
secondHalfStart: 後半の切り出し開始位置(奇数のとき中央を重複させるためcenter-1) -
firstS: 禁止単語の前半 -
secondS: 禁止単語の後半
🔹単語ごとの検閲処理
for (const word of V) {
if (S.length !== word.length) {
console.log(word);
continue;
}
if (word === S) {
console.log('banned');
continue;
}
const firstHalf = word.slice(0, firstHalfEnd);
const secondHalf = word.slice(secondHalfStart);
-
長さが違えば処理不要、そのまま出力
-
完全一致は
"banned"出力 -
それ以外の場合、対象単語を前半・後半に分割
🔹前半・後半の比較と置き換え処理
if (firstHalf === firstS) {
if (odd) {
console.log(secondHalf.slice(1).padStart(word.length, 'x'));
} else {
console.log(secondHalf.padStart(word.length, 'x'));
}
} else if (secondHalf === secondS) {
if (odd) {
console.log(firstHalf.slice(0, firstHalf.length-1).padEnd(word.length, 'x'));
} else {
console.log(firstHalf.padEnd(word.length, 'x'));
}
} else {
console.log(word);
}
}
- 前半一致
- 残すのは「後半」
- 奇数長なら中央がかぶるため
slice(1)で先頭を除去 - 残した部分を
.padStart(targetLength, padString)で全長に合わせて"x"で埋める
- 後半一致
- 残すのは「前半」
- 奇数長なら中央がかぶるため最後を削る
- 残した部分を
.padEnd()で全長に合わせて"x"で埋める
- どちらも一致しない
- そのまま出力
📝まとめ
🔹奇数長文字列の中央は前後どちらにも含める
-
center = Math.ceil(S.length / 2)を基準に切り分ける
🔹slice を活用して前半・後半を取り出す
firstHalf = word.slice(0, firstHalfEnd)secondHalf = word.slice(secondHalfStart)
🔹中央の重複調整
- 前半一致時 → 後半側の先頭を削る (
slice(1)) - 後半一致時 → 前半側の末尾を削る (
slice(0, -1))
🔹padStart / padEnd で 禁止部分を "x" に。
- 後半を残す場合 →
.padStart() - 前半を残す場合 →
.padEnd()
🔹処理の流れ
- 長さチェック
- 完全一致チェック
- 前半一致 / 後半一致判定
- 検閲処理して出力