✏️ 문제 설명
n1개의 원소로 이루어져 있는 수열 A의 정보와, n2개의 원소로 이루어져 있는 수열 B의 정보가 주어졌을 때 수열 B가 수열 A의 연속부분수열인지를 판단하는 프로그램을 작성해보세요.
수열 B가 수열 A의 원소들을 연속하게 뽑았을 때 나올 수 있는 수열이라면 연속부분수열이라 부릅니다.
예를 들어 수열 A가 [1, 5, 2, 6] 일때 수열 B가 [5, 2]라면 수열 B는 수열 A의 연속 부분 수열이지만, 만약 수열 B가 [5, 6]이라면 연속 부분 수열이 아닙니다.
✏️ code
💻 슬라이딩 윈도우 알고리즘
- 이거 왜 써야 돼?
- 슬라이딩 윈도우 알고리즘은 배열, 리스트 데이터 구조에서 연속된 부분 배열의 합, 최대값 등을 효율적으로 계산하는데 사용합니다.
- 왜 효율적일까? 반복적인 계산을 줄여 시간 복잡도를 낮출 수 있기 때문입니다.
- 일반적으로 고정된 크기의 윈도우를 사용하여 데이터를 처리합니다.
- 👉🏻 본 문제에서는 전체 배열을 반복적으로 탐색하는 대신, 현재 윈도우의 변화만 추적하는 방식으로 중복 계산을 최소화하고자 슬라이딩 윈도우 알고리즘을 사용했습니다.
- 슬라이딩 윈도우 알고리즘의 개념
- 고정된 크기의 윈도우를 사용하여 데이터를 처리하는 알고리즘입니다.
- 고정된 크기의 윈도우를 시작 부분으로 설정, 그 윈도우를 배열이나 리스트에서 한 칸씩 오른쪽으로 이동
- 윈도우가 이동할 때마다, 윈도우에 포함된 요소들을 검사(필요한 작업 수행)
- 슬라이딩 윈도우 알고리즘의 예제
- 최대 부분 배열 합
- 고정된 크기의 부분배열 평균
- 문자열의 아나그램 찾기
- 주식 가격의 이동 평균 계산
📌 고민했던 부분
- isSubsequence 함수에서 슬라이딩 윈도우 알고리즘 적용
- for (int i = 0; i <= n1 - n2; i++)
- n1 - n2을 한 이유는 이 이상의 값으로 i가 넘어갈 경우, 어차피 n2 즉 arr2.length를 넘어서게 되기 때문입니다.
- 넘을 경우 NullPointerException이 발생할 것으로 예상되었고, 이는 불필요한 계산이기도 하기 때문에 n1 - n2를 했습니다.
- if (arr1[i+j] != arr2[j])
- 입력값이 아래와 같은 경우
4 2
1 5 6 2
5 6
- 입력값이 아래와 같은 경우
- for (int i = 0; i <= n1 - n2; i++)
i+j | j | 비교 값 |
0+0 | 0 | arr1[0] = 1 != arr2[0] = 5 true -> break |
1+0 | 0 | arr1[1] = 5 != arr2[0] = 5 false -> 계속 비교 |
1+1 | 1 | arr1[2] = 6 != arr2[1] = 6 false -> 비교 종료 |
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine().trim());
int n1 = Integer.parseInt(st.nextToken());
int n2 = Integer.parseInt(st.nextToken());
int arr1[] = new int[n1];
int arr2[] = new int[n2];
StringTokenizer st1 = new StringTokenizer(br.readLine().trim());
for (int i = 0; i < n1; i++) {
arr1[i] = Integer.parseInt(st1.nextToken());
}
StringTokenizer st2 = new StringTokenizer(br.readLine().trim());
for (int i = 0; i < n2; i++) {
arr2[i] = Integer.parseInt(st2.nextToken());
}
System.out.print(isSubsequence(arr1, arr2) ? "Yes" : "No");
br.close();
}
private static boolean isSubsequence(int arr1[], int arr2[]) {
int n1 = arr1.length;
int n2 = arr2.length;
for (int i = 0; i <= n1-n2; i++) {
boolean match = true;
for (int j = 0; j < n2; j++) {
if (arr1[i+j] != arr2[j]) {
match = false;
break;
}
}
if (match) {
return true;
}
}
return false;
}
}
반응형
'Java > 코딩테스트' 카테고리의 다른 글
[프로그래머스/181847] 0 떼기 (w. 정규표현식, String.replaceFirst()) (0) | 2024.12.30 |
---|---|
[코드트리/NL] 중복되지 않는 정수 중 최대 (w. HashMap, Math.max) (0) | 2024.12.29 |
[코드트리/NL] 나눗셈의 나머지 (1) | 2024.12.25 |
[코드트리/NL] 특정 규칙에 따른 숫자 출력 (0) | 2024.12.22 |
[Java/백준/Bronze II] 소수 찾기 - 1978, 리팩토링(Scanner, split → BufferedReader, StringTokenizer) (1) | 2024.09.16 |