https://www.acmicpc.net/problem/11005
문제
10진법 수 N이 주어진다. 이 수를 B진법으로 바꿔 출력하는 프로그램을 작성하시오.
10진법을 넘어가는 진법은 숫자로 표시할 수 없는 자리가 있다. 이런 경우에는 다음과 같이 알파벳 대문자를 사용한다.
A: 10, B: 11, ..., F: 15, ..., Y: 34, Z: 35
입력
첫째 줄에 N과 B가 주어진다. (2 ≤ B ≤ 36) N은 10억보다 작거나 같은 자연수이다.
출력
첫째 줄에 10진법 수 N을 B진법으로 출력한다.
예제 입력 1
60466175 36
예제 출력 1
ZZZZZ
풀이과정
2745번 진법 변환 문제와 비슷하게 진법 변환을 위한 파이썬 내장 함수가 있을 것이라고 생각해서 먼저 구글링을 했다.
그런데 10진법 수를 n진법으로 변환하는 건 직접 코드를 작성해야 한다고..! 😨
그래서 다른 블로그 글을 참고하여 코드를 짰다.
import string
import sys
input = sys.stdin.readline
tmp = string.digits+string.ascii_uppercase
def convert(num, base) :
q, r = divmod(num, base)
if q == 0 :
return tmp[r]
else :
return convert(q, base) + tmp[r]
num,base = map(int, input().split()) # num: 10진법 수, base: 변환하려는 진법수
print(convert(num,base))
tmp는 출력해보니 다음과 같았다.
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ
divmod() 함수를 사용해 num을 base로 나눈 몫을 q에, 나머지를 r에 저장한다.
그리고 만약 몫이 없다면 tmp 문자열에서의 나머지(r)번째 위치를 return 한다.
만약 몫이 있다면 다시 q와 base에 대해 convert() 함수를 실행해 구하고, 그 문자열 값에 tmp[r]을 더한다.
다른 블로그 글을 참고했지만, 괜찮은 풀이라고 생각하고 백준 채점을 돌렸는데,,
대충격.. 시간이 144ms이 걸렸다.. 높은 순위의 다른 파이썬 풀이를 보니 36ms면 돌아갈 수 있는 문제였는데..
아마 내 풀이에서는 재귀함수를 통한 풀이 때문에 많은 시간이 소요됐나보다.
아무튼 그래서 정리해보고자 하는 다른 풀이는 다음과 같다.
ans = ''
x, y = map(int, input().split())
while x:
r = x % y
if 0 <= r <= 9:
ans += str(r)
else:
ans += chr(ord('A') + r - 10)
x //= y
print(ans[::-1])
입력받은 10진수 수를 x로, 진법을 y로 나타낸다.
x가 존재하는 한 계속해서 반복한다.
r은 x를 y로 나눈 나머지이고, 이 값이 0에서 9 사이의 숫자이면 정답 문자열에 문자열로 더한다.
만약 r이 숫자가 아니면, 즉 10 이상의 수이면 알파벳으로 나타낸다. 이를 위해 chr(ord('A') + r - 10)로 계산한다.
예를들어, r이 12이면 A: 10, B: 11, ..., F: 15, ..., Y: 34, Z: 35이므로 C로 나타나져야 한다.
따라서 A의 아스키코드 값(55) + r(12) - 10 = 57(C의 아스키코드값) 을 구한 후 이를 다시 chr() 함수를 통해 유니코드 문자로 변환한다.
현재 계산한 나머지 값 r에 대한 10진수 변환이 끝났다면 x를 y로 나눈 몫을 다시 x에 넣고 반복한다.
x가 0이 되면 반복이 종료되고, 현재 반대 순서로 정답이 저장되었으므로 [::-1]을 통해 문자열을 뒤집어 결과를 출력한다.
몫과 나머지, 그리고 아스키코드를 이렇게 이용하는게 왜 생각이 안날까... 더 많이 공부하자!!