🔗 문제 링크
이 문제는 고대의 주문서에 기록된 모든 주문(알파벳 소문자 11글자 이하로 구성된 모든 문자열)이
다음 규칙에 따라 정렬되어 있다고 가정합니다.
예를 들어, 주문서의 시작 부분은
"a" → "b" → ... → "z" → "aa" → "ab" → ... → "zz" → ...
와 같이 구성됩니다.
그러나 주문서에는 저주받은 주문들이 포함되어 있어, 일부 주문은 삭제되었습니다.
문제의 목표는, 삭제된 주문들을 고려하여 실제 주문서에서 n번째 주문이 무엇인지 찾는 것입니다.
문제 해결을 위한 주요 아이디어는 숫자 n을 주문서의 순서대로 변환하는 것입니다.
즉, "n번째 주문"을 구하는 함수 getString(n)
을 작성하여,
숫자 n을 위에서 설명한 정렬 순서(길이 우선, 길이가 같으면 사전 순)대로 대응되는 문자열로 변환합니다.
Math.pow
는 부동소수점 연산을 사용하기 때문에,getString
메서드에서 Math.pow를 제거하고,if (cur.length() < target.length() || cur.compareTo(target) <= 0)
와 같이 되어 있었는데,if (cur.length() < target.length() || (cur.length() == target.length() && cur.compareTo(target) <= 0))
이렇게 하면, banned에 저장된 문자열이 후보 문자열보다 앞쪽에 위치할 때만아래 코드는 위의 아이디어를 모두 반영한 최종 풀이입니다.
import java.util.*;
import java.io.*;
// Math.pow를 사용하면 부동소수점 연산으로 인한 오버헤드가 발생할 수 있으므로,
// 반복문과 정수 연산을 이용하여 26진법 변환을 수행합니다.
class Solution {
public String solution(long n, String[] bans) {
// banned 주문들을 길이, 사전순으로 정렬
Queue<String> bansQueue = new ArrayDeque<>();
Arrays.sort(bans, (o1, o2) -> {
if (o1.length() == o2.length()) return o1.compareTo(o2);
return o1.length() - o2.length();
});
for (int i = 0; i < bans.length; i++) {
bansQueue.add(bans[i]);
}
// banned 주문들보다 순서가 앞에 있는 주문이 있으면 n을 증가시킴.
// 조건: banned 주문의 길이가 현재 n번째 주문(getString(n))보다 짧거나,
// 길이가 같을 경우 사전순으로 같거나 앞서 있으면.
while (!bansQueue.isEmpty()) {
String cur = bansQueue.peek();
String target = getString(n);
if (cur.length() < target.length() || (cur.length() == target.length() && cur.compareTo(target) <= 0)) {
bansQueue.poll();
n++;
} else {
break;
}
}
return getString(n);
}
// getString: 숫자 n을 주문서의 순서에 맞는 문자열로 변환
// 변환 방식: 26진법 변환과 유사하게 처리하며, n이 26의 배수인 경우를 따로 처리함.
private String getString(long n) {
StringBuilder sb = new StringBuilder();
while (n > 0) {
long remained = n % 26;
n /= 26;
if (remained == 0) {
n--;
sb.append('z');
} else {
sb.append((char)('a' + remained - 1));
}
}
return sb.reverse().toString();
}
}
bans 정렬 및 큐 초기화
Arrays.sort(bans, ...)
를 이용해 banned 주문들을 먼저 길이 순으로 정렬하고,bansQueue
에 추가합니다.banned 주문 처리
getString(n)
을 호출하여 현재 n번째 주문(후보 문자열)을 구합니다.cur
)을 비교합니다.cur
의 길이가 후보 문자열보다 짧다면,cur
는 후보보다 앞쪽에 있으므로 banned에 포함되어 있으므로 n을 증가시켜 건너뜁니다.cur.compareTo(target) <= 0
라면,cur
가 후보와 같거나 사전순으로 앞서면 역시 n을 증가시켜 건너뜁니다.n번째 주문 문자열 반환
getString(n)
을 호출하여, banned 주문들을 고려한 실제 n번째 주문 문자열을 반환합니다.getString 메서드 (26진법 변환 방식)