백준 2531 - 회전 초밥
Updated:
Java
2531 번 - 회전 초밥
문제
- 임의의 한 위치부터 k개 접시를 연속하여 먹는다.
- 보너스로 하나의 스시(c)를 제공한다.
가능한 한 다양한 종류의 초밥을 먹으려고 한다.
회전 초밥 음식점의 벨트 상태, 메뉴에 있는 초밥의 가짓수, 연속해서 먹는 접시의 개수, 쿠폰 번호가 주어졌을 때, 손님이 먹을 수 있는 초밥 가짓수의 최댓값을 구하는 프로그램을 작성하시오.
2 ≤ N ≤ 30,000, 2 ≤ d ≤ 3,000, 2 ≤ k ≤ 3,000 (k ≤ N), 1 ≤ c ≤ d
접근 방법
스시의 순서대로 0부터 n-1까지 탐색하여, k개의 스시를 매번 탐색해 종류의 세는 방식으로 해결하면, O(n^2)의 시간으로 시간초과이다.
따라서, Sliding window를 통하여 해결하였다.
먼저 처음 인덱스 0에서부터 k개만큼의 스시를 선택한다.
해당하는 k개의 스시로 탐색한 다음, 제일 앞의 스시를 하나 제거하고 제일 뒤에 스시를 하나 추가하여 한번 더 탐색한다. 따라서, k 크기의 window를 오른쪽으로 하나씩 이동하며 탐색하여 초밥 가짓수의 최댓값을 구한다.
스시를 추가하고 제거할 때마다, 지금까지 기록된 스시 타입의 개수를 증감하며 현재 스시 타입의 개수를 구한다.
코드
import java.util.*;
import java.io.*;
public class Main {
static int n, d, k, c, result;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stk = new StringTokenizer(br.readLine());
n = stoi(stk.nextToken());
d = stoi(stk.nextToken());
k = stoi(stk.nextToken());
c = stoi(stk.nextToken());
int[] sushi = new int[n * 2];
for(int i = 0; i < n; i++)
sushi[i] = stoi(br.readLine());
int[] type = new int[d + 1];
for(int i = 0; i < k; i++)
sushi[n + i] = sushi[i];
int cnt = 0;
// 스시 추가
for(int i = 0; i < k; i++) {
// 만약 처음 넣는 스시이면
if(type[sushi[i]] == 0) {
cnt++;
}
type[sushi[i]]++; // 해당 스시의 개수 증가
}
// 보너스 스시 추가
if(type[c] == 0) {
cnt++;
}
type[c]++;
result = cnt;
for(int i = k; i < n + k - 1; i++) {
// 앞 포인터의 스시 제거
type[sushi[i - k]]--;
if(type[sushi[i - k]] == 0) // 더 이상 해당 스시가 없으면
cnt--;
// 뒤 포인터의 스시 추가
if(type[sushi[i]] == 0) { // 새로 추가된 스시이면
cnt++;
}
type[sushi[i]]++;
result = Math.max(result, cnt);
}
System.out.println(result);
br.close();
}
static int stoi(String str) {
return Integer.parseInt(str);
}
}
총평
후기
알고리즘 분류의 두 포인터를 보고 아이디어를 얻어 푼 문제.
개선할 점
없습니다.