두 개의 숫자 n과 k가 주어졌다고 가정해 보겠습니다. 이때 우리는 길이가 k이면서 거리가 n이 되는, 사전순(lexicographically)으로 가장 작은 소문자 문자열을 찾아야 합니다.
여기서 말하는 거리(distance)는 문자열을 이루는 각 알파벳의 번호를 모두 더한 값입니다. 예를 들어 'a'는 1번, 'b'는 2번, 'y'는 25번, 'z'는 26번입니다.
따라서 입력이 n = 15, k = 3이라면 출력은 "aam"이 됩니다. "aam"의 거리는 1 + 1 + 13 = 15이며, 거리가 15인 길이 3의 문자열 중에서 사전순으로 가장 앞에 오는 문자열이기 때문입니다.
알고리즘 접근 방법
이 문제의 핵심 아이디어는 그리디(Greedy) 방식입니다. 사전순으로 가장 작은 문자열을 만들려면 앞쪽 문자들을 가능한 한 'a'(값 1)에 가깝게 유지하고, 남은 무게를 뒤쪽 문자들에 최대한 몰아주는 것이 유리합니다. 각 문자는 최대 'z'(값 26)까지 커질 수 있으므로, 기본값 1에서 시작해 한 문자당 최대 25만큼 더할 수 있습니다.
구체적인 풀이 단계는 다음과 같습니다.
- 크기가 k인 배열
dist를 만들고 모든 값을 1로 초기화합니다. credit := n - k로 설정합니다. (추가로 분배해야 할 무게)i := k - 1로 설정합니다. (배열의 마지막 인덱스부터 시작)credit > 0인 동안 다음을 반복합니다.val := credit과 25 중 더 작은 값dist[i] := dist[i] + valcredit := credit - vali := i - 1
dist의 각 값 d에 대해chr(d - 1 + ord("a"))로 문자를 변환한 뒤, 이를 하나로 연결하여 반환합니다.
예제 코드
다음 파이썬 구현을 통해 더 자세히 이해해 보겠습니다.
def solve(n, k):
dist = [1] * k
credit = n - k
i = k - 1
while credit > 0:
val = min(credit, 25)
dist[i] += val
credit -= val
i -= 1
return "".join(chr(d - 1 + ord("a")) for d in dist)
n = 15
k = 3
print(solve(n, k))
입력
15, 3
출력
aam
동작 원리 정리
위 코드에서 먼저 모든 문자를 'a'로 초기화한 상태(합 = k)에서 출발합니다. 그런 다음 목표 거리까지 부족한 만큼(n - k)을 뒤쪽 문자부터 순서대로 채워 넣습니다. 한 문자가 26('z')을 초과하지 않도록 한 번에 최대 25만 더하기 때문에, 결과적으로 앞쪽에는 'a'가 많이 남고 무거운 문자들이 뒤쪽에 배치되어 사전순으로 가장 작은 문자열이 완성됩니다.