임의의 DNA 문자열(A, C, G, T)에서 부분 문자열을 뽑았을 때, 등장하는 각 문자의 개수가 특정 기준 이상인 경우의 수를 구하는 문제입니다.
윈도우의 크기가 로 고정되어 있으므로, 한 칸씩 이동할 때마다 '새로 들어오는 문자'와 '나가는 문자'만 업데이트하면 의 시간 복잡도로 해결할 수 있습니다.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws Exception {
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
StringTokenizer st = new StringTokenizer(br.readLine());
int s = Integer.parseInt(st.nextToken());
int p = Integer.parseInt(st.nextToken());
char[] dna = br.readLine().toCharArray();
st = new StringTokenizer(br.readLine());
int[] need = new int[4]; // A, C, G, T 최소 개수
for (int i = 0; i < 4; i++) {
need[i] = Integer.parseInt(st.nextToken());
}
int i = 0, j = 0, answer = 0;
int[] count = new int[4]; // 현재 윈도우 내 문자 카운트
while (j < s) {
// 1. 새로운 문자 추가 (Window Expand)
count[idx(dna[j++])]++;
// 2. 윈도우 크기가 P에 도달했을 때
if (j - i == p) {
if (isFullfill(count, need)) {
answer++;
}
// 3. 가장 오래된 문자 제거 (Window Shrink)
count[idx(dna[i++])]--;
}
}
System.out.println(answer);
}
}
// 조건 만족 여부 확인
private static boolean isFullfill(int[] count, int[] need) {
for (int k = 0; k < 4; k++) {
if (count[k] < need[k]) return false;
}
return true;
}
// 문자별 인덱스 매핑
private static int idx(char c) {
switch (c) {
case 'A': return 0;
case 'C': return 1;
case 'G': return 2;
case 'T': return 3;
default: return -1;
}
}
}
idx() 메서드를 통해 char 데이터를 정수 인덱스로 변환하여 배열 연산의 편의성을 높였습니다.슬라이딩 윈도우는 '고정 구간'의 데이터를 연속적으로 처리해야 할 때 가장 먼저 떠올려야 하는 기법입니다. 중복 계산을 피하고 변화량만 기록하는 이 방식은 대규모 데이터 처리에서 필수적인 테크닉입니다.