문제
https://www.acmicpc.net/problem/1593
마야 문자를 해독하는 일은 예상 외로 어려운 일이다. 현재에도 뜻이 완전히 밝혀진 마야 문자는 거의 없는 실정이며, 그나마 해독에 진척이 시작된 지는 30여 년도 되지 않았다.
마야 문자는 소리를 나타내는 여러 종류의 그림글자로 구성되는데, 이 글자들이 여러 위치에서 결합함으로써 단어를 형성한다.
마야 문자 해독을 어렵게 하는 요인 중 하나는 바로 단어를 읽는 순서이다. 마야 문자를 쓰는 고대인들은 단어를 기록할 때 특정한 규칙 대신, 그들이 보기에 좋게 보이도록 단어를 이루는 글자들을 아무렇게나 배열했다. 그렇기 때문에 고고학자들이 마야 기록에서 단어를 이루는 각 그림글자들의 발음을 알아내더라도 그 단어를 실제로 발음하는 방법은 정확히 알 수 없는 셈이다.
고고학자들은 W라는 특정 단어를 발굴 기록으로부터 찾고 있다. 그 단어를 구성하는 각 글자들은 무엇인지 알고 있지만, 이것이 고대 기록에 어떤 형태로 숨어 있는지는 다 알지 못한다.
W를 이루고 있는 g개의 그림문자와, 연구 대상인 벽화에 기록된 마야 문자열 S가 주어졌을 때, 단어 W가 마야 문자열 S에 들어있을 수 있는 모든 가짓수를 계산하는 프로그램을 작성하시오. 즉, 문자열 S안에서 문자열 W의 순열 중 하나가 부분 문자열로 들어있는 모든 경우의 수를 계산하라는 뜻이다.
입력
첫째 줄에 고고학자들이 찾고자 하는 단어 W의 길이 g와 발굴된 벽화에서 추출한 문자열 S의 길이 |S|가 빈 칸을 사이에 두고 주어진다. (1≤g≤3000, g≤|S|≤3,000,000) 둘째 줄에 W, 셋째 줄에 S의 실제 내용이 들어있다. 모든 문자열은 알파벳으로 이루어지며, 대소문자를 구분한다.
출력
첫째 줄에 W의 순열이 S 안에 있을 수 있는 형태의 개수를 출력한다.

풀이
1. 문자열 W와 S를 비교하기 위해 각 문자의 등장 횟수를 객체에 저장한다. 동일한 문자가 여러 번 등장할 수 있으므로, 문자의 개수를 누적하여 카운트한다.
2. 초기 윈도우(문자열 S의 앞부분)에 대한 문자 빈도 정보를 isSame 함수를 통해 W와 비교한다. 두 객체의 문자가 모두 동일한 개수로 등장한다면 일치하는 경우로 판단하고, 정답 카운트를 증가시킨다.
3. 이후 슬라이딩 윈도우 기법을 사용하여 문자열 S를 한 글자씩 오른쪽으로 이동시킨다. 새로 들어온 문자는 추가하고, 빠져나간 문자는 개수를 줄인다. 이때 개수가 0이 된 문자는 객체에서 제거한다. 매 이동마다 isSame 함수를 통해 현재 윈도우와 W를 비교하고, 같을 경우 정답 카운트를 증가시킨다.
4. 최종 계산된 정답 카운트를 출력한다.
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin").toString().trim().split("\n");
const [g, s] = input[0].split(" ").map(Number);
const W = input[1];
const S = input[2];
const wMap = {};
const sMap = {};
let answer = 0;
for (let i = 0; i < g; i++) {
const wCh = W[i];
const sCh = S[i];
wMap[wCh] = (wMap[wCh] || 0) + 1;
sMap[sCh] = (sMap[sCh] || 0) + 1;
}
const isSame = (a, b) => {
for (let key in a) {
if (a[key] !== b[key]) return false;
}
return true;
};
if (isSame(wMap, sMap)) answer++;
for (let i = g; i < s; i++) {
const add = S[i];
const remove = S[i - g];
sMap[add] = (sMap[add] || 0) + 1;
sMap[remove]--;
if (sMap[remove] === 0) delete sMap[remove];
if (isSame(wMap, sMap)) answer++;
}
console.log(answer);
결론
골드 5 난이도의 슬라이딩 윈도우 문제이다.
문자열 비교에는 객체를 활용하여 각 문자의 등장 횟수를 기록하였다.
W와 S의 윈도우 길이는 같기 때문에, 두 객체의 key를 기준으로 value(문자 개수)만 비교하면 효율적으로 문제를 해결할 수 있다.
'코딩테스트' 카테고리의 다른 글
[백준] 전자레인지 (JS) (0) | 2025.05.22 |
---|---|
[백준] DNA 비밀번호 (JS) (0) | 2025.05.19 |
[백준] 줄줄이 박수 (JS) (0) | 2025.05.15 |
[백준] 문자열 교환 (JS) (0) | 2025.05.12 |
[백준] 우당탕탕 영화예매 (JS) (0) | 2025.05.09 |