문제
ㅋㅋ루ㅋㅋ 문자열은 다음과 같이 정의한다.
- R로만 이루어진 문자열은 ㅋㅋ루ㅋㅋ 문자열이다. 단, 빈 문자열은 ㅋㅋ루ㅋㅋ 문자열이 아니다.
- ㅋㅋ루ㅋㅋ 문자열 양 끝에 K를 하나씩 붙인 문자열은 ㅋㅋ루ㅋㅋ 문자열이다.
입력
첫째 줄에 K와 R로만 이루어진 문자열이 주어진다. 문자열의 길이는 최대 3,000,000이다.
출력
주어진 문자열의 부분 수열 중 가장 긴 ㅋㅋ루ㅋㅋ 문자열의 길이를 출력한다. 부분 수열 중 ㅋㅋ루ㅋㅋ인 문자열이 없는 경우, 0을 출력한다.
풀이
결국 선택되는 형태는 K ... K + R...R + K ... K다. 가운데에 고른 R 묶음의 양옆에 몇 개의 K를 붙일 수 있는지가 중요하다.
코드에서는 먼저 전체 R의 개수를 세고, 각 R 기준으로 왼쪽에 있는 K 개수와 오른쪽에 있는 K 개수를 각각 배열처럼 저장한다. 그러면 left번째 R부터 right번째 R까지를 가운데 묶음으로 택했을 때, 붙일 수 있는 K 수는 양쪽 중 더 작은 값으로 결정된다.
이후 R들 위에서 투 포인터를 움직인다. 현재 양쪽 K 가능 개수 중 작은 쪽이 병목이므로, 그쪽 포인터를 줄이는 방식으로 최적해를 찾는다. 매번 후보 길이는 가운데 R 개수 + 2 * min(왼쪽 K, 오른쪽 K)가 된다.
코드
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String input = br.readLine();
int ans = solve(input);
System.out.println(ans);
}
static int solve(String input) {
int rCnt = getRCnt(input);
List<Integer> leftK = checkLeftK(input);
List<Integer> rightK = checkRightK(input);
int ans = 0;
int cnt = rCnt;
int left = 0;
int right = rCnt - 1;
while (left <= right) {
if (leftK.get(left) < rightK.get(right)) {
ans = Math.max(ans, leftK.get(left) * 2 + cnt);
left++;
} else {
ans = Math.max(ans, rightK.get(right) * 2 + cnt);
right--;
}
cnt--;
}
return Math.max(ans, rCnt);
}
// R 개수 구하기
static int getRCnt(String input) {
int rCnt = 0;
for (int i = 0; i < input.length(); i++)
if (input.charAt(i) == 'R')
rCnt++;
return rCnt;
}
// R 기준 왼쪽에 있는 누적 K개수 구하기
static List<Integer> checkLeftK(String input) {
List<Integer> leftK = new ArrayList<>();
int kCnt = 0;
for (int i = 0; i < input.length(); i++) {
if (input.charAt(i) == 'R')
leftK.add(kCnt);
else
kCnt++;
}
return leftK;
}
// R 기준 오른쪽에 있는 누적 K개수 구하기
static List<Integer> checkRightK(String input) {
List<Integer> rightK = new ArrayList<>();
int kCnt = 0;
for (int i = input.length() - 1; i >= 0; i--) {
if (input.charAt(i) == 'R')
rightK.add(kCnt);
else
kCnt++;
}
Collections.reverse(rightK);
return rightK;
}
}복잡도
- 시간 복잡도:
- 공간 복잡도:
마무리
문자열 정의는 귀엽지만, 실제로는 가운데 R 구간과 양옆 K 개수의 균형을 보는 문제다. 양쪽 중 작은 쪽이 항상 병목이라는 점 때문에 투 포인터가 잘 맞는다.
