일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 레이아웃 스래싱
- 값복사
- 레퍼런스복사
- webpack5
- next14
- 즉시실행함수
- 백준
- 이벤트 생명주기
- webpack
- SW EA
- vscode
- 마진 상쇄
- 렌더링 최적화
- react
- 정적타입언어
- 누적합
- 공백찾기
- 이분탐색
- 분할정복
- 리액트
- 구현
- react18
- BFS
- 슬라이딩 윈도우
- 브루트포스
- 재귀
- 두 포인터
- 수학
- 동적타입언어
- 컴포넌트 생명주기
- Today
- Total
D.JOUNG
백준 문제풀이 : (12891) DNA 비밀번호 - C/C++ 본문
문제 : https://www.acmicpc.net/problem/12891
12891번: DNA 비밀번호
평소에 문자열을 가지고 노는 것을 좋아하는 민호는 DNA 문자열을 알게 되었다. DNA 문자열은 모든 문자열에 등장하는 문자가 {‘A’, ‘C’, ‘G’, ‘T’} 인 문자열을 말한다. 예를 들어 “ACKA”
www.acmicpc.net
시간 제한 | 메모리 제한 | 난이도 | 알고리즘 분류 |
2초 | 512 MB | Silver 2 | 문자열, 슬라이딩 윈도우 |
문제
풀이
슬라이딩 윈도우란 '두 포인트' 알고리즘응 응용한 알고리즘으로, 두 포인터 사이의 구간을 지정하고 해당 구간을 n칸씩 옮겨가며 문제를 해결하는 방식이다.
어떤 조건을 만족하는 연속된 구간의 개수를 구할 때 유용하게 사용할 수 있으며, 두 포인터와 마찬가지로 실행횟수가 N번이므로 아주 경제적이다.
문제에서는 길이가 S인 특정 문자열이 주어졌을 때, 그 속에서 조건을 만족하는 길이 P의 문자열을 몇 개 만들 수 있는 지 물어보고 있다. 즉, 길이 P의 문자열이 되는 조건은 아래와 같다.
1) 길이 P의 문자열의 구성원은 길이 S의 문자열의 연속된 값이다.
2) 길이 P의 문자열은 조건 'ACGT'을 만족한다.
여기서 조건 ACGT란 문자 A,C,G,T가 입력에서 주어진 횟수 대로 문자열 내에 포함되어있는 지를 뜻한다.
풀이법은 슬라이딩 윈도우 알고리즘을 그대로 대입해, 다음의 순서대로 진행하면 된다.
1) 첫 번째 포인터(start)와 두 번째 포인터(end)의 처음 주소를 0번지로 지정한다.
2) end의 주소를 p-1번지 까지 1씩 증가시킨다.
2-1) 2를 반복하는 과정에서, end가 지나는 주소의 문자가 A, C, B, T 중 하나라면 해당 문자의 개수를 1 증가한다.
3) 2까지 진행했을 경우, start는 0번지에, end는 p-1번지 혹은 p번지에 있을 것이다. (for문 사용 시 end가 p번지로 이동 후 반복이 끝난다.)
4) 새로운 반복을 시작한다.
4-1) 세어둔 A, C, B, T의 개수가 조건에 부합하면 count를 1 증가한다.
4-2) start가 가리키는 번지의 문자가 A, C, B, T 중 하나라면 해당 문자의 개수를 1 감소한다.
4-3) start 번지수를 1 증가한다.
4-4) end가 가리키는 번지의 문자가 A, C, B, T 중 하나라면 해당 문자의 개수를 1 증가한다.
4-5) end 번지수를 1 증가한다.
5) end가 s번지를 가리키면 모든 문자열을 검사했으므로 반복을 종료한다.
6) count를 출력한다.
이처럼, start와 end 사이를 검사 중인 문자열 구간으로 정하고 한 칸 우측으로 이동할 때 마다 A, C, G, T의 변화를 체크하며 조건에 맞는 문자열 구간의 수를 구한다.
코드 작성
#include <iostream>
using namespace std;
typedef struct ACGT {
int a = 0;
int c = 0;
int g = 0;
int t = 0;
} ACGT; //가독성을 위해 a, c, g, t의 개수를 구조체로 관리
void setPlusACGT(int num, ACGT* flag) {
//end가 이동할 때, 새로 영역에 들어오는 문자를 판별 후 개수를 +1 해줌.
switch(num) {
case 'A' : flag->a++; break;
case 'C' : flag->c++; break;
case 'G' : flag->g++; break;
case 'T' : flag->t++; break;
default : break;;
}
}
void setMinusACGT(int num, ACGT* flag) {
//start가 이동할 때, 영역에서 제외되는 (가장 앞) 문자를 판별 후 개수를 -1 해줌.
switch(num) {
case 'A' : flag->a--; break;
case 'C' : flag->c--; break;
case 'G' : flag->g--; break;
case 'T' : flag->t--; break;
default : break;;
}
}
int main() {
int s, p;
scanf("%d %d\n", &s, &p);
char str[s+1];
scanf("%s\n", str);
int a, c, g, t;
scanf("%d %d %d %d", &a, &c, &g, &t);
ACGT flag;
int start=0, end=0, count=0;
for ( ; end<p ; end++) { //end를 한 칸씩 이동하며 구간에 한 문자씩 포함함.
setPlusACGT(str[end], &flag); //문자 개수 체크
}
while(end<=s) {
if (flag.a>=a && flag.c>=c && flag.g>=g && flag.t>=t) {
//현재 구간 속 문자열이 조건에 부합한다면 count++
count++;
}
setMinusACGT(str[start++], &flag); //end의 이동에 따른 구간 내 문자 개수 체크
setPlusACGT(str[end++], &flag); //start의 이동에 따른 구간 내 문자 개수 체크
}
printf("%d", count);
return 0;
}
'알고리즘 > 백준' 카테고리의 다른 글
백준 문제풀이 : (1654) 랜선 자르기 - C/C++ (1) | 2024.02.07 |
---|---|
백준 문제풀이 : (1913) 달팽이 - C/C++ (1) | 2024.02.03 |
백준 문제풀이 : (1253) 좋다 - C/C++ (2) | 2023.12.21 |
백준 문제풀이 : (2166) 다각형의 면적 - C/C++ (0) | 2023.12.14 |
백준 문제풀이 : (17386) 선분 교차 1, 두 직선의 기울기로 문제 풀기 - C/C++ (0) | 2023.12.13 |