[프로그래머스][LV.0] 배열 만들기 2 | python3
2025. 2. 3. 18:41ㆍ프로그래머스/LV.0
문제 링크: 배열 만들기 2
문제 설명
문제 설명
정수 l과 r이 주어졌을 때, l 이상 r이하의 정수 중에서 숫자 "0"과 "5"로만 이루어진 모든 정수를 오름차순으로 저장한 배열을 return 하는 solution 함수를 완성해 주세요.
만약 그러한 정수가 없다면, -1이 담긴 배열을 return 합니다.
제한사항
- 1 ≤ l ≤ r ≤ 1,000,000
문제 풀이
좀 전에 풀어서 기억이 안나는데 아마 안풀려서 참고 해서 풀었던 것 같다. 그리고 다시 풀려고 보니 지금도 낑낑 거리는 게 레전드....
그래 그냥 5와 0 외의 숫자가 있으면 그냥 넘기면 된다.
다시 풀려고 봤을때 r의 최대 숫자가 너무 커서 for문으로 돌려도 되나? 싶었는데(시간상) 상관없었나봄...
시간복잡도에 대해서도 제대로 공부해야 할 거 같다.
그리고 이 문제를 보니 기억이 났다. 이거 분명 뭔가 이진수를 이용해서 풀 수 있을 거 같다고 생각하고 그냥 넘겨서 따로 빼 놓은 문제였다.
내코드
def solution(l, r):
answer = []
for n in range(l,r+1):
if str(n) in ['1','2','3','4','6','7','8','9']:
continue
elif str(n) in ['1','2','3','4','6','7','8','9'] and str(n) in ['0']:
continue
elif str(n) in ['1','2','3','4','6','7','8','9'] and str(n) in ['5']:
continue
else:
answer.append(n)
if not answer:
return [-1]
return sorted(answer)
더보기
다른사람풀이
def solution(l, r):
answer = []
number = ['0', '5']
for i in range(l, r+1):
now = str(i)
now_in = True
for j in now:
if j not in number:
now_in = False
break
if now_in == True:
answer.append(i)
if answer:
return answer
else:
return [-1]
리스트에 0과 5만 두고 다른 숫자가 나오면 바로 브레이크를 해버려서 빠져나온다.
for문을 두개나 도는데 과연 어느쪽이 더 빠를까??/
gpt한테 물어보니 이 코드가 훨씬 빠르다고 한다.
♠ 내 코드의 문제점
문제점
- str(n) in ['1','2','3','4','6','7','8','9'] 검사가 잘못됨
- str(n) 자체가 리스트 ['1','2','3','4','6','7','8','9']에 포함되는지 확인하는 코드인데, 이건 n이 한 자리 숫자가 아닐 때 항상 False가 됨.
- 예를 들어 n=50일 때 str(n) == "50", 즉 "50" in ['1','2','3','4','6','7','8','9']는 False라서 필터링이 안 됨.
- elif 조건이 의미 없음
- elif str(n) in ['1','2','3','4','6','7','8','9'] and str(n) in ['0']:
- str(n)이 ['1','2','3','4','6','7','8','9']에 포함되면서 동시에 ['0']에도 포함되어야 함.
- 즉, 하나의 문자열이 ['0']과 ['1','2','3','4','6','7','8','9']에 동시에 포함될 수 없으므로 항상 False.
- elif str(n) in ['1','2','3','4','6','7','8','9'] and str(n) in ['5']:
- 위와 같은 이유로 항상 False.
- elif str(n) in ['1','2','3','4','6','7','8','9'] and str(n) in ['0']:
- sorted(answer)가 불필요
- answer는 이미 오름차순으로 추가되기 때문에 sorted()를 호출할 필요가 없음.
- 속도가 느린 이유
- str(n) 변환이 불필요하게 여러 번 발생.
- 잘못된 if-elif 조건이 많아서 불필요한 연산 수행.
- 최악의 경우 O(N)의 시간복잡도인데, 불필요한 조건 검사로 인해 오히려 더 느려짐.
♠ 이 코드의 장점
장점
- 올바른 조건 검사
- 숫자를 문자열로 변환한 후, 각 자리 숫자가 '0' 또는 '5'만 포함하는지 검사.
- for j in now:를 통해 자리 수 하나하나 검사하며, '0' 또는 '5'가 아닌 숫자가 나오면 break로 중단.
- 시간 단축 효과가 있음.
- 불필요한 sorted() 없음
- 리스트에 추가하는 순서가 이미 정렬된 상태이므로 정렬이 필요 없음.
- 빠른 탐색 구조
- 숫자의 자리수를 검사하는 방식이므로 최악의 경우에도 O(KN) (K는 숫자의 자릿수, 최대 6).
- 첫 번째 코드보다 훨씬 빠름.
♠ 두 코드 속도 비교
- 최악의 경우 (l=1, r=1,000,000)
- 첫 번째 코드: 불필요한 연산이 많아 더 느림.
- 두 번째 코드: 숫자를 문자열로 변환한 뒤 자리수를 검사하는 방식이라 상대적으로 빠름.
- 숫자 범위가 커질 때 (예: l=1, r=10,000,000)
- 첫 번째 코드는 r+1까지 for 문을 도는 방식이라 더 심각하게 느려짐.
- 두 번째 코드도 느려지지만, 불필요한 연산이 적기 때문에 그나마 더 빠름.
더 개선된 코드도 알려줬다..
def solution(l, r):
answer = []
for i in range(l, r+1):
if set(str(i)) <= {'0', '5'}:
answer.append(i)
return answer if answer else [-1]
def solution(l, r):
answer = [num for num in range(l, r + 1) if set(str(num)) <= {'0', '5'}]
return answer if answer else [-1]
def solution(l, r):
answer = []
for num in range(l, r + 1):
if not set(str(num)) - set(['0', '5']):
answer.append(num)
return answer if answer else [-1]
다른사람코드에 비슷한 코드가 있었다.
이 코드의 장점
- set(str(i)) <= {'0', '5'}:
- 문자열을 set으로 변환하면 중복 없이 숫자만 남음.
- 예를 들어 "550" → {'5', '0'}인데, {'5', '0'}가 {'0', '5'}의 부분집합이면 올바른 숫자.
- 불필요한 for 루프 제거, 더 간결함.
- 최악의 경우에도 O(KN)
- 기존 코드보다 연산이 줄어듦.
- set 비교 연산이 빠르므로 최적화 효과가 큼.
** set의 비교연산자는 부분집합으로 계산한다.
def solution(l, r):
answer = []
for i in range(l, r+1):
if all([num in ['0', '5'] for num in str(i)]):
answer.append(i)
if len(answer) == 0:
answer.append(-1)
return answer
♣ all() 함수 동작
all() 함수는 리스트의 모든 값이 True인지 확인하는 함수입니다.
all([True, True, True]) # True all([False, False, False]) # False all([True, False, True]) # False
적용 예제
✅ 숫자가 '0'과 '5'로만 이루어진 경우 (i = 505)
if all([True, True, True]): # all()이 True 반환 answer.append(505)
✔️ 505는 answer 리스트에 추가됨.
❌ 숫자에 '0'과 '5' 이외의 숫자가 포함된 경우 (i = 123)
if all([False, False, False]): # all()이 False 반환 answer.append(123) # 실행 안 됨
❌ 123은 answer에 추가되지 않음.
def solution(l, r):
answer = []
i = 1
n = 5
while True:
if n > r: break
n = 5 * int(bin(i)[2:])
if l <= n <= r:
answer.append(n)
i += 1
return [-1] if len(answer) == 0 else answer
이진법풀이....이렇게 생각해서 옮길 수 있다는 게 신기하다.
def solution(l, r):
ret = []
def f(lim, val):
if lim == 0:
ret.append(val)
return
f(lim - 1, val * 10 + 5)
f(lim - 1, val * 10)
f(6, 0)
return list(i for i in ret if l <= i <= r)[::-1] or [-1]
이진법과 재귀함수 풀이
'프로그래머스 > LV.0' 카테고리의 다른 글
[프로그래머스][LV.0] 문자열 여러 번 뒤집기 | python3 (0) | 2025.02.03 |
---|---|
[프로그래머스][LV.0] 주사위 게임 3 | python3 (0) | 2025.02.03 |
[프로그래머스][LV.0] 숫자 비교하기 | python3 (0) | 2025.01.14 |
[프로그래머스][LV.0] 몫 구하기 | python3 (0) | 2025.01.14 |
[프로그래머스][LV.0] 두 수의 합, 두 수의 차, 두 수의 곱 | python3 (0) | 2025.01.14 |