문제
자연수 N의 분해합은 N과 N의 각 자리수를 더한 값이다. 예를 들어, 245의 분해합은 다음과 같다.
245 + 2 + 4 + 5 = 256
이때, 245는 256의 생성자가 된다. 생성자는 여러 개일 수 있으며, 생성자가 없는 경우도 있다.
우리의 목표는 주어진 자연수 N에 대해 가장 작은 생성자를 찾는 것이다.
배경지식
이 문제는 브루트 포스 알고리즘 단계에 들어가 있다. 브루트 포스 알고리즘에 대해 간단히 알아보자면, 브루트(Brute)는 무식한 이라는 뜻이다. 한마디로 무식하게 다 해보는 알고리즘을 브루트 포스 알고리즘이라고 한다.
논리 및 아이디어
1. 값을 입력받는다.(입력받은 값: n)
2. 1부터 n-1까지 해당 숫자와 자릿수를 모두 더해 생성자인지 확인한다.
3. 생성자가 맞다면 반복문을 깨고 나온다.
나의 풀이
코드
num = int(input())
testnum = 0
SumOfComposition = False
while testnum < num:
totsum = testnum
for i in str(testnum):
totsum += int(i)
if totsum == num:
SumOfComposition = True
break
testnum += 1
if SumOfComposition:
print(testnum)
else:
print(0)
코드 설명
num
에 입력값을 저장한다.testnum
을 0으로 초기화하고,SumOfComposition
을 False로 설정한다.while
루프를 통해testnum
이num
보다 작을 동안 반복한다.totsum
에testnum
값을 저장하고,testnum
의 각 자리수를 더한다.totsum
이num
과 같으면SumOfComposition
을 True로 설정하고 루프를 종료한다.- 루프가 종료되면
SumOfComposition
의 값에 따라testnum
또는 0을 출력한다.
다른 코드
코드
n = int(input())
result = 0
for i in range(1, n):
a = list(map(int, str(i)))
s = i + sum(a)
if s == n:
result = i
break
print(result)
코드 설명
n
에 입력값을 저장한다.result
를 0으로 초기화한다.for
루프를 통해 1부터n-1
까지 반복한다.i
를 문자열로 변환한 후, 각 자리수를 정수로 변환하여 리스트a
에 저장한다.i
와a
의 합을 계산하여s
에 저장한다.s
가n
과 같으면result
에i
를 저장하고 루프를 종료한다.- 루프가 종료되면
result
를 출력한다.
코드 비교 및 분석
공통점
- 두 코드 모두 브루트 포스 방식을 사용하여 1부터 N까지의 모든 수를 탐색한다.
- 각 자리수를 더하는 방법으로 분해합을 계산한다.
차이점
두 코드는 거의 비슷하다. 그러나 실행시간이 더 오래 걸렸다. 다른 코드1의 코드를 여러 번 다시 실행해본 결과 평균적으로 300ms 걸렸다.
자릿수를 더하는 과정이 그 원인이라고 생각한다. for문으로 직접 더하는 방식보다 map과 list를 이용하는 방식은 코드는 간단하지만 오버헤드가 더 클 수 있다.
개선할 점
무엇보다 탐색을 1부터 n-1까지 모두 할 필요가 없었다.
1. 탐색하는 수가 일정 이상 커지면 모든 자릿수를 더하면 생성자가 될 수 없다.
2. 각 자릿수는 최대 9이다. 3자리 수는 각 자릿수가 9일 때, 자릿수의 합이 27이므로, (N-27) 부터 N-1까지만 탐색하면 된 다. 2자리 수는 18을 뺀 수부터 탐색하면 될 것이다. 따라서 최적화된 범위는 N - (N의 자리수 * 9) 부터 N-1까지이다.
- 탐색 범위 최적화: 생성자는 최대
N - (N의 자리수 * 9)
까지 가능하므로, 탐색 범위를 줄이면 실행 속도가 빨라진다. - 자리수 합 계산 간소화:
map
과sum
함수를 사용하여 더 간결한 코드를 작성할 수 있다. - 코드 가독성 향상: 변수명을 명확하게 하고, 불필요한 변수를 제거하여 더 깔끔한 코드를 만들 수 있다.
최적의 코드
n = int(input())
for i in range(max(1, n - len(str(n)) * 9), n):
if i + sum(map(int, str(i))) == n:
print(i)
break
else:
print(0)
개선된 코드 설명
n
에 입력값을 저장한다.for
루프를 통해 가능한 생성자 범위를 탐색한다.i
와i
의 각 자리수의 합이n
과 같으면i
를 출력하고 루프를 종료한다.- 루프가 종료될 때까지 생성자를 찾지 못하면 0을 출력한다.
출처
'Python > 백준 문제풀이' 카테고리의 다른 글
[백준 파이썬 4134번] 다음소수 모든 풀이 비교 분석 (0) | 2024.10.30 |
---|---|
[백준 13909번 파이썬]'창문닫기' 모든 풀이 비교 분석 (0) | 2024.10.17 |
[백준 2485번 파이썬]'가로수' 모든 풀이 비교 분석 (0) | 2024.10.15 |
[백준 2903번 파이썬]'중앙이동 알고리즘' 모든 풀이 비교 분석 (1) | 2024.09.05 |
[백준 11653번 파이썬]'소인수분해' 모든 풀이 비교 분석 (2) | 2024.09.02 |