<aside> 💡 슬라이딩 윈도우 알고리즘은 2개의 포인터로 범위를 지정한 다음 **범위(window)를 유지한 채로 이동(sliding)**하며 문제를 해결한다. 투 포인터 알고리즘과 매우 비슷하고 원리도 간단.
</aside>



**[A, C, G, T]**
1 0 0 1 **A와 T가 들어있어야 함.**
**GATA**
GA -> X
AT -> O
TA -> O




<aside> 💡 업데이트할 때 빠지는 문자열, 신규 문자열만 보고 업데이트 하는 방식이 무슨 말이냐면, [C, C , T, G, G, A, T, T, G] 배열에서 C는 빠지고 G가 추가되는 것을 의미함. 이렇게 되면 중간에 있는 문자열들이 아무리 길어도 상관이 없다. (이전에도 있었기 때문)
</aside>

public class DNA_12891 {
static int[] myArr = new int[4]; // {0,0,0,0};
static int[] ACGT = new int[4]; //{2,0,1,1};
static int checkSecret = 0; // 만족하는 수. 4개가 만족해야 함
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer tokenizer = new StringTokenizer(bufferedReader.readLine());
int S = Integer.parseInt(tokenizer.nextToken()); // 문자열 길이
int P = Integer.parseInt(tokenizer.nextToken()); // 부분 문자열 길이
int result = 0;
char[] sArr = new char[S]; // 처음에 들어오는 전체 문자열
// 데이터 입력 부분
sArr = bufferedReader.readLine().toCharArray();
tokenizer = new StringTokenizer(bufferedReader.readLine());
for(int i=0; i < 4; i++) {
ACGT[i] = Integer.parseInt(tokenizer.nextToken());
// 0인 경우에는 무시해도 됨. (checkSecret++)
if(ACGT[i] == 0) {
checkSecret++;
}
}
// 부분 문자열 처음 받을 때 셋팅 (전체 중 첫 번째 슬라이드)
for(int i=0; i < P; i++) {
add(sArr[i]);
}
if(checkSecret == 4) {
result++;
}
// 슬라이딩 윈도우. 여기부터는 오른쪽으로 한 칸 이동한 부분부터 처리를 함.
for(int i=P; i < S; i++) {
int j = i-P; // 8-8, 9-8, 10-8...범위를 유지하면서 이동함.
// 한칸씩 이동할 때 빠지는 애와 들어가는 애만 체크하면 됨.
add(sArr[i]); // 새로 들어가는 부분
remove(sArr[j]); // 빠지는 부분
if(checkSecret == 4) {
result++;
}
}
System.out.println(result);
}
private static void remove(char c) {
switch (c) {
case 'A':
if(myArr[0] == ACGT[0])
checkSecret--;
myArr[0]--;
break;
case 'C':
if(myArr[1] == ACGT[1])
checkSecret--;
myArr[1]--;
break;
case 'G':
if(myArr[2] == ACGT[2])
checkSecret--;
myArr[2]--;
break;
case 'T':
if(myArr[3] == ACGT[3])
checkSecret--;
myArr[3]--;
break;
}
}
private static void add(char c) {
switch (c) {
case 'A':
myArr[0]++;
if(myArr[0] == ACGT[0])
checkSecret++;
break;
case 'C':
myArr[1]++;
if(myArr[1] == ACGT[1])
checkSecret++;
break;
case 'G':
myArr[2]++;
if(myArr[2] == ACGT[2])
checkSecret++;
break;
case 'T':
myArr[3]++;
if(myArr[3] == ACGT[3])
checkSecret++;
break;
}
}
}