문제 소개
두 개의 양수 n과 k가 주어졌을 때, 다음 규칙에 따라 이진 문자열 Sn을 만들 수 있다고 가정해 보겠습니다.
- S1 = 0
- i > 1인 경우, Si = Si-1 + "1" + reverse(invert(Si-1))
여기서 reverse(x)는 문자열 x를 거꾸로 뒤집은 결과를 반환하고, invert(x)는 x의 모든 비트를 반전합니다(0은 1로, 1은 0으로).
이 규칙으로 만들어진 처음 네 개의 문자열은 다음과 같습니다.
- S1 = "0"
- S2 = "011"
- S3 = "0111001"
- S4 = "011100110110001"
구해야 하는 것은 Sn에서 k번째 비트의 값입니다.
예를 들어 입력이 n = 4, k = 10이라면 출력은 1입니다. S4 = "011100110110001"에서 10번째 비트가 1이기 때문입니다(첫 번째 비트의 위치를 1로 계산).
해결 접근 방법
k가 1이면 어떤 문자열이든 첫 번째 비트는 항상 0이므로 바로 "0"을 반환하면 됩니다. 그 외의 경우에는 필요한 길이에 도달할 때까지 문자열을 단계별로 확장해 나가는 방식을 사용합니다.
핵심은 두 개의 배열을 함께 관리하는 것입니다.
- arr: 현재 단계의 이진 문자열에 해당하는 배열
- arr2: arr을 비트 반전한 뒤 거꾸로 뒤집은 값, 즉 reverse(invert(arr))를 저장하는 배열
arr의 길이가 k보다 작은 동안 아래 과정을 반복합니다.
- templast := arr의 복사본
- temp2last := arr2의 복사본
- arr := templast + [1] + temp2last
- arr2 := templast + [0] + temp2last
반복이 끝나면 arr의 (k−1)번째 요소가 곧 정답이 됩니다.
예제 코드
def solve(n, k):
if k == 1:
return(str(0))
else:
arr = [0]
arr2 = [1]
while k > len(arr):
templast = arr.copy()
temp2last = arr2.copy()
arr = templast + [1] + temp2last
arr2 = templast + [0] + temp2last
return(str(arr[k-1]))
n = 4
k = 10
print(solve(n, k))
입력
4, 10
출력
1
동작 원리
각 단계에서 새 문자열의 길이는 '이전 길이 × 2 + 1'이 됩니다. 따라서 S1의 길이는 1, S2는 3, S3은 7, S4는 15이며, 일반적으로 Si의 길이는 2i − 1입니다.
코드에서 arr2는 항상 reverse(invert(arr))라는 성질을 유지합니다. 그래서 다음 단계의 문자열을 만들 때 이 값을 그대로 뒤에 붙이기만 하면 되고, 매번 새로 반전·역순 연산을 수행할 필요가 없습니다. 이 덕분에 로직이 단순해지고, 시간 복잡도는 목표 위치 k에 비례하는 O(k) 수준으로 유지됩니다.