작년에 이어 새로운 문자열 게임이 있다. 게임의 진행 방식은 아래와 같다.
위와 같은 방식으로 게임을 회 진행한다.
문자열 게임의 수 가 주어진다.
다음 줄부터 개의 줄 동안 문자열 와 정수 가 주어진다.
개의 줄 동안 문자열 게임의 번과 번에서 구한 연속 문자열의 길이를 공백을 사이에 두고 출력한다.
만약 만족하는 연속 문자열이 없을 시 을 출력한다.
부분 문자열에서 특정 문자가 정확히 개인 것 중 길이의 최소와 최대를 동시에 구하는 문제입니다.
처음 생각한 것은 두 개의 최소와 최대에 대한 두 개의 투 포인터 메서드를 구현하자는 생각이었지만 그렇게 조잡하게 문제를 제출하지 않았을 것이고 다른 방법과 의도가 있을 것이라고 생각했습니다.
그래서 정답을 정해놓지 않고 순차적으로 할 수 있는 것들을 해나갔습니다.
부분 문자열에서 특정 문자가 개가 되는지를 확인하려면 알파벳을 계수 정렬 방식으로 카운팅을 해야겠다는 생각을 먼저 하게 되었고 alphabet이라는 정수형 배열을 선언합니다.
그리고 난 후 한 번의 문을 돌리면서 alphabet[spelling[i] - 97]++ 연산을 수행했습니다.
이후 alphabet 배열을 확인해보니 각 알파벳의 출현 개수가 를 넘지 않는 알파벳이 많은 것을 알 수 있었고
그러면 알파벳 단위로 최댓값, 최솟값을 구하는 로직을 구현하자는 생각을 하게 되었습니다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
int T = Integer.parseInt(br.readLine());
while (T-- > 0) {
char[] spellings = br.readLine().toCharArray();
int K = Integer.parseInt(br.readLine());
startGame(spellings, K, sb);
}
System.out.println(sb);
}
static void startGame(char[] spellings, int K, StringBuilder sb) {
int L = spellings.length;
int[] alphabet = new int[26];
for (char c : spellings) {
alphabet[c - 97]++;
}
int min = L + 1;
int max = -1;
for (int i = 0; i < 26; i++) {
if (alphabet[i] < K) continue;
char target = (char)(i + 97);
int[] memo = new int[alphabet[i]];
int index = 0;
for (int end = 0; end < L; end++) {
if (spellings[end] == target) {
memo[index] = end;
index++;
}
}
for (int start = 0; start <= alphabet[i] - K; start++) {
int end = K + start - 1;
int currentLength = memo[end] - memo[start] + 1;
min = Math.min(min, currentLength);
max = Math.max(max, currentLength);
}
}
if (min == L + 1 || max == -1) sb.append("-1");
else sb.append(min).append(" ").append(max);
sb.append("\n");
}
}