今回は paiza の「シフト管理」の問題に挑戦!
問題概要
- paizaマートの アルバイトのシフト管理 を行う問題
- 1日は 0時〜23時の24時間 に分かれている
- 各バイトには
- シフト開始時間
S_i - シフト終了時間
E_i
が与えられる
- シフト開始時間
- シフトは
- 開始時刻は含む
- 終了時刻は含まない(半開区間
[S_i, E_i))
-
S_i > E_iの場合は 日をまたぐシフト(例:21 → 6) - 1人のシフトは最大23時間まで
判定条件
- すべての時間帯(0〜23時)で
- シフトに入っている人数が 2人以上
- 条件を満たす →
"OK" - 1時間でも満たさない →
"NG"
入力例:
5
17 22
9 20
21 6
4 13
22 5
出力例:
NG
✅OK例:
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const lines = [];
rl.on('line', line => {
lines.push(line);
});
rl.on('close', () => {
let idx = 0;
// バイト人数
const N = Number(lines[idx++]);
// 各時間帯(0〜23時)の人数をカウントする配列
const partTimeMember = Array(24).fill(0);
// 各バイトのシフトを処理
for (let i = 0; i < N; i++) {
let [S, E] = lines[idx++].split(' ').map(Number);
// 開始時刻から終了時刻まで1時間ずつカウント
// 終了時刻は含まない(S === E になったら終了)
while (S !== E) {
partTimeMember[S]++;
S++;
S %= 24; // 日をまたぐ場合の処理
}
}
let ans = "OK";
// 全ての時間帯で2人以上いるか確認
for (let i = 0; i < 24; i++) {
if (partTimeMember[i] < 2) {
ans = "NG";
}
}
// 結果出力
console.log(ans);
});
🔍コードの流れ
- 標準入力(
readline)で入力を1行ずつ受け取る - 入力がすべて終わったら処理を開始する
- 最初の行からバイト人数
Nを読み取る - 0〜23時の各時間帯ごとに、人数を数える配列を用意する
- 各バイトについて以下を繰り返す
- シフトの開始時刻
Sと終了時刻Eを読み取る -
SからEまで、1時間ずつ進めながら人数をカウントする - 終了時刻
Eの時間帯はカウントしない - 日をまたぐシフトは
24で割った余りを使って処理する
- シフトの開始時刻
- 24時間すべての時間帯について
- シフトに入っている人数が2人未満の時間があるかを確認する
- 全時間帯で2人以上いれば
"OK"、そうでなければ"NG"を出力する
📝まとめ
時間区間の扱い
- シフトは
[開始, 終了)(終了を含まない) -
while (S !== E)やfor (j = S; j < E; j++)が自然な書き方
日跨ぎ処理
-
S > Eを特別扱いしなくても -
S = (S + 1) % 24で統一的に処理できる
配列での集計
- 「時間帯 × 人数」は 配列1本で管理できる
- 問題を「時間ごとの人数チェック問題」に落とし込む