회전 초밥
문제 요약
회전 초밥 벨트에서 연속으로 K 개의 접시를 먹을 때, 중복되지 않는 초밥 종류의 최대 개수를 구하되, 쿠폰으로 제공되는 초밥(c번 초밥)을 하나 더 먹을 수 있다면 포함시킨다. 벨트는 원형이므로 끝에서 시작으로 이어진다.
적용 알고리즘
이 문제는 연속된 구간의 정보를 빠르게 갱신 해야 하므로 슬라이딩 윈도우 가 적합하다.
특정 범위의 초밥 종류 수를 효율 적으로 관리하기 위해 Map
또는 배열
을 이용한 카운팅 을 사용한다.
Java 코드
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nectInt(); // 접시 수
int d = sc.nextInt(); // 초밥 가짓수
int k = sc.nextInt(); // 연속으로 먹는 접시 수
int c = sc.nextInt(); // 쿠폰 번호
int[] arr = new int[N]; // 초밥 벨트
for(int i = 0; i < N; i++) {
arr[i] = sc.nextInt();
}
int[] count = new int[d + 1]; // 각 초밥 종류의 먹은 개수 카운트
int unique = 0;
//초기 윈도우 설정
for(int i = 0; i < k; i++) {
int sushi = arr[i % N];
if(count[sushi] == 0) unique++; // 처음 먹는 종류묜 증가
count[sushi]++;
}
// 쿠폰 초밥 처리
if(count[c] == 0) unique++;
int max = unique;
//슬라이딩 윈도우 : 총 N 번만 이동해보면 충분(원형 구조 고려)
for(int i = 1; i < N; i++) {
//윈도우 맨 앞 제거
int remove = arr[(i - 1) % N];
count[remove]--;
if(count[remove] == 0 && remove != c) unique--; // 종류 빠지면 감소
// 윈도우 새로 추가
int add = arr[(i + k - 1) % N];
if(count[add] == 0) unique++;
count[add]++;
// 쿠폰 초밥이 이미 포함되어 있지 않다면 보너스로 +1
int current = unique;
if(count[c] == 0) current++;
max = Math.max(max, current);
max = Math.max(max, current);
}
System.out.println(max);
}
}
요약
슬라이딩 윈도우를 이용해 연속 구간을 탐색
초밥 중복을 count 배열로 관리
쿠폰 초밥은 항상 포함 여부를 확인하여 + 1 처리
원형 벡트를 인덱스
%N
으로 처리하여 회전 구현
Last updated
Was this helpful?