728x90
https://www.acmicpc.net/problem/12891
📝 유튜브 풀이 (이론)
- 슬라이딩 윈도우 알고리즘
: 2개의 포인터로 범위(크기)를 지정 한 다음 다음 범위(크기)를 유지한 채로 이동하면서 문제를 해결
O(n)의 시간 복잡도
📝 유튜브 풀이 (풀이)
https://www.youtube.com/watch?v=52O6CiUrslc&list=PLFgS-xIWwNVU_qgeg7wz_aMCk22YppiC6&index=7
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
static int myArr[];
static int checkArr[];
static int checkSecret;
public static void main(String[] args) throws IOException {
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());
int Result = 0;
checkArr = new int[4];
myArr = new int[4];
char A[] = new char[S];
checkSecret = 0;
A = br.readLine().toCharArray();
st = new StringTokenizer(br.readLine());
for(int i=0; i<4; i++) {
checkArr[i] = Integer.parseInt(st.nextToken());
//만족해야하는 조건이 0인 경우 입력 되지 않아도 조건을 만족하기 떄문에
if(checkArr[i]==0) {
checkSecret++;
}
}
for(int i=0; i<P; i++) {
//부분 문자열 처음 받을 때 세팅
Add(A[i]);
}
if(checkSecret==4) Result++;
//슬라이딩윈도우
for(int i=P; i<S; i++) {
//범위를 유지하면서 한칸 옮겨가는 효과
int j=i-P;
Add(A[i]);
Remove(A[j]);
if(checkSecret ==4) Result++;
}
System.out.println(Result);
br.close();
}
private static void Remove(char c) {
switch (c) {
case 'A':
if(myArr[0]==checkArr[0]) checkSecret--;
myArr[0] --;
break;
case 'C':
if(myArr[1]==checkArr[1]) checkSecret--;
myArr[1] --;
break;
case 'G':
if(myArr[2]==checkArr[2]) checkSecret--;
myArr[2] --;
break;
case 'T':
if(myArr[3]==checkArr[3]) checkSecret--;
myArr[3] --;
break;
}
}
private static void Add(char c) {
switch (c) {
case 'A':
myArr[0] ++;
if(myArr[0]==checkArr[0]) checkSecret++;
break;
case 'C':
myArr[1] ++;
if(myArr[1]==checkArr[1]) checkSecret++;
break;
case 'G':
myArr[2] ++;
if(myArr[2]==checkArr[2]) checkSecret++;
break;
case 'T':
myArr[3] ++;
if(myArr[3]==checkArr[3]) checkSecret++;
break;
}
}
}
📝 나의 풀이
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.StringTokenizer;
public class Main {
static int S,P,answer;
static String DNA;
// DNA 문자열
static char[] dna = {'A','C','G','T'};
static HashMap<Character,int[]> hashMap = new HashMap<Character, int[]>();
public static void main(String[] args) throws IOException {
// DNA 문자열 = 모든 문자열에 등장하는 문자가 ‘A’, ‘C’, ‘G’, ‘T’인 문자열
// 부분문자열에 ‘A’ 는 1개 이상, ‘C’는 1개 이상, ‘G’는 1개 이상, ‘T’는 0개 이상이 등장해야 비밀번호로 사용가능
// 부분문자열이 등장하는 위치가 다르다면 부분문자열이 같다고 하더라도 다른 문자열로 취급
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
// 문자열의 길이
S = Integer.parseInt(st.nextToken());
// 부분 문자열의 길이
P = Integer.parseInt(st.nextToken());
//입력받을 문자
DNA = br.readLine();
st = new StringTokenizer(br.readLine());
for(char c : dna) {
/* dna 문자 , {현재 카운트 , 최소조건 }
첫 번째 요소는 현재 카운트 값이므로 초기상태에서는 아무 카운트가 되지 않아 0으로 초기화
최소조건은 Integer.parseInt(st.nextToken())을 통해 입력받음 */
hashMap.put(c, new int[] {0, Integer.parseInt(st.nextToken())});
}
// P만큼 자른 문자열을 카운트하고 isFull()을 이용해 조건을 만족하는지 체크
for(int i=0; i<P; i++) {
/* 문자열 "CCTGGATT"를 순회하며, 각 문자가 A, C, G, T인지 확인하고 해당하는 카운트를 증가
문자 'C'가 2번 등장하므로 hashMap.get('C')[0]를 2로 업데이트
문자 'T'가 2번 등장하므로 hashMap.get('T')[0]를 2로 업데이트
*/
hashMap.get(DNA.charAt(i))[0]++;
}
if(isFull()) answer++;
/* hashMap.get(DNA.charAt(i)) => hashmap 의 DNA.charAt(i)를 불러온다.
인덱스를 1씩 증가시키면서 가장 왼쪽 문자를 삭제하고 가장 오른쪽 문자는 추가한다.
카운트를 0으로 초기화 하지 않고 첫 번째 요소의 카운트 값을 1으로 감소시킨다.
예를 들어 CCTGGATTG의 경우 "CCTGGATT"를 확인한 뒤 "CTGGATTG"를 확인 할 때,
첫 번째 C문자가 제거 되었기 때문에 카운트 값을 1 감소시키는 것
*/
for(int i=0; i<S-P; i++) {
hashMap.get(DNA.charAt(i))[0] -= 1;
hashMap.get(DNA.charAt(i+P))[0] += 1;
if(isFull()) answer++;
}
System.out.println(answer);
}
public static boolean isFull() {
for(char c:dna) {
/* for문에서 입력받은 DNA문자를 한문자씩 가져와서
hashMap.get(c)[0] = c의 첫번째 요소를 가져옴
hashMap.get(c)[1] = c의 두번째 요소를 가져옴
예를들어
9 8
CCTGGATTG
2 0 1 1
에서 A의 최소조건은 '2'이지만 hashMap.get('A')[0]는 1이므로 최소 조건보다 작음
첫 번째 요소가 두 번째 요소보다 작다면 false 를 return
= DNA 문자열이 최소 조건을 만족하지 않는 경우 */
if(hashMap.get(c)[0] < hashMap.get(c)[1]) {
return false;
}
}
//DNA 문자열이 최소 조건을 만족하지 않는 경우
return true;
}
}
728x90
'코딩테스트 > [JAVA] 백준' 카테고리의 다른 글
[백준 | JAVA | 1874번] 스택 수열 (1) | 2023.11.15 |
---|---|
[백준 | JAVA | 11721번] 열 개씩 끊어 출력하기 (1) | 2023.11.14 |
[백준 | JAVA | 4134번] 다음 소수 (0) | 2023.11.11 |
[백준 | JAVA | 2485번] 가로수 (0) | 2023.11.10 |
[백준 | JAVA | 2018번] 수들의 합 5 (2) | 2023.11.08 |