투 포인터 알고리즘은 배열이나 리스트를 탐색할 때 두 개의 포인터를 활용하는 방법으로, 보통 연속된 부분 배열을 찾거나, 특정 조건을 만족하는 값을 효율적으로 탐색할 때 사용된다.
💡 완전 탐색(Brute Force, O(N²))보다 훨씬 빠른 O(N) 시간 복잡도를 가질 수 있습니다.
import java.io.*;
import java.util.*;
class Main {
/**
* 과일의 개수 n
* 앞 또는 뒤쪽에서 과일을 빼서 두 종류 이하의 과일만 남겨야 함
*/
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
int[] fruitArr = new int[n];
st = new StringTokenizer(br.readLine());
for (int i = 0; i < n; i++) {
fruitArr[i] = Integer.parseInt(st.nextToken());
}
System.out.println(getMaxFruit(fruitArr, n));
}
public static int getMaxFruit(int[] fruitArr, int n) {
// 투 포인터 (start: 왼쪽 포인터, end: 오른쪽 포인터)
int start = 0;
int maxLength = 0;
// 현재 윈도우 내 과일 종류와 개수를 저장하는 HashMap
HashMap<Integer, Integer> fruitMap = new HashMap<>();
// 오른쪽 포인터(end)를 이동하며 탐색
for (int end = 0; end < n; end++) {
// 현재 과일을 윈도우에 추가
fruitMap.put(fruitArr[end], fruitMap.getOrDefault(fruitArr[end], 0) + 1);
// 과일 종류가 3개 이상이면, 왼쪽 포인터(start)를 이동하여 조절
while (fruitMap.size() > 2) {
// start 위치의 과일 개수 감소
fruitMap.put(fruitArr[start], fruitMap.get(fruitArr[start]) - 1);
// 만약 해당 과일 개수가 0이 되면 map에서 제거
if (fruitMap.get(fruitArr[start]) == 0) {
fruitMap.remove(fruitArr[start]);
}
// left 포인터 이동 (불필요한 과일 제거)
start++;
}
// 현재 윈도우 크기(과일 개수) 갱신
maxLength = Math.max(maxLength, end - start + 1);
}
// 가장 긴 구간 반환
return maxLength;
}
}