📌 문제 : 로또 번호 생성기
- input 함수로 사용자 입력을 받아, 총 6개의 숫자를 만들어준다.
💡 입력
- 모든 자연수 가능, 1번만 입력
- 아무 자연수 6개를 골라, 콤마(',')를 기준으로 순서대로 입력
▶ 들어온 입력 처리 → 모든 숫자가 1-45 사이가 되도록 한다.
💡 예외
- 생성한 6개의 숫자 중, 중복 존재 → 둘 중 큰 숫자에 +1
- 이때, 45를 넘으면 1로 return
- 만약, number_list 중복된 값이 존재하면 해당 값들의 기존 리스트 값을 비교하고, 기존 값이 더 큰 것에 +1
💡 결과
- make_lotto_number 함수에서 number_list return
# 실행 예시
>>> 입력 : 4151361,13597019,222,123315,4,13516
>>> 출력 : [45, 17, 38, 35, 4, 39]
# 실행 예시2
>>> 입력 : 1370519,12970,1,4747475758,8079013768590167835917,22
>>> 출력 : [41, 44, 1, 34, 25, 22]
# 실행 예시3
>>> 입력 : 17239407190457, 178278, 1111, 14595971035597, 33, 55
>>> 출력 : [31, 28, 7, 8, 33, 9]
(원래 [31, 28, 7, 7, 33, 9]인데, 1111보다 14595971035597이 더 크므로 +1을 해줌.)
문제를 보자마자 처음 든 생각은 이거였다.
(리스트에 중복값이 존재할 때, 굳이 원본 값이랑 비교를 해야하나? 그냥 +1 해주면 되는데 왜 귀찮게..)
🌐 # 코드 1
def make_lotto_number(string):
"""
input 함수를 통해 입력받은 변수를 string이라는 parameter로 넘겨줍니다.
해당 string을 처리하여 6개의 1 ~ 45 사이의 숫자를 가지는 리스트를 만들어서 return 합니다.
"""
string_list = list(string)
number_list = []
num = 0
for i in range(6):
num = string_list[i] % 46
print(num)
if num > 45:
num = 1
if num in number_list:
num = num + 1
number_list.append(num)
return number_list
# 1 : 4151361,13597019,222,123315,4,13516 => [45, 17, 38, 35, 4, 39]
# 2 : 1370519,12970,1,4747475758,8079013768590167835917,22 => [41, 44, 1, 34, 25, 22]
# 3 : 17239407190457, 178278, 1111, 14595971035597, 33, 55 => [31, 28, 7, 8, 33, 9]
input_num = list(map(int, input().split(',')))
print(make_lotto_number(input_num))
오랜만에 파이썬 다루기도 하고 손 풀 겸 대충 짜봤다.
하지만 과제이니.. 하라는 대로 해야지!
🌐 # 코드 2
def make_lotto_number(string):
string_list = list(string)
number_list = []
num = 0
for i in range(6):
max = -1
num = string_list[i] % 46
if (num > 45 or num < 1):
num = 1
# print('num: ', num, '------------------------------------')
# 중복 제거
if num in number_list:
idx = number_list.index(num)
if(string[idx] > string[i]): max = idx
else: max = i
if (num > 45 or num < 1):
num = 1
number_list.append(num)
# print('전:', number_list[-1])
if(max > -1):
# print('max: ', max)
number_list[max] = number_list[max] + 1
# print('후:', number_list[max])
print('number_list: ', number_list, '=======================')
return number_list
# 1 : 4151361,13597019,222,123315,4,13516 => [45, 17, 38, 35, 4, 39]
# 2 : 1370519,12970,1,4747475758,8079013768590167835917,22 => [41, 44, 1, 34, 25, 22]
# 3 : 17239407190457, 178278, 1111, 14595971035597, 33, 55 => [31, 28, 7, 8, 33, 9]
input_num = list(map(int, input().split(',')))
print(make_lotto_number(input_num))
여전히 마음에 안 드는 점이 몇 가지 있었다.
1. num > 45일 때, 1로 초기화시켜주는 위치가 마음에 안 든다.
2. 예외(중복 존재 값)를 2가지가 같다고 단정짓지 말고 2가지 이상의 수를 비교했을 때도 잘 되는가?를 실험해봐야 한다.
3. 숫자가 1부터 46까지 나와야 하는데, 46 입력시 나머지가 0이다. (n % 46을 썼으니까) 하지만, 모든 숫자가 1-45 사이로 뽑혀야 하므로 고쳐야 한다.
3-1. 그냥 % 45로 했다. 리모트에서 제시한 실행 예시랑 출력값이 다르다.
3-2. 리모트에서 제시한 % 46을 썼다. 만약, 46과 47이 주어졌을 때 & 46을 하면 [0, 1]이 된다. 0은 1-45 사이가 아니니, +1을 해주면 [1, 1]이 되어버리고, 46 < 47 이기 때문에 [1, 2]가 된다. 이때, ex. 49 % 46 = 3인데, 얘는 3으로 그대로 쓰는지? 아니면 앞에 값들을 다 +1 해줬으니, 얘도 +1을 해줘야하는가?에 대한 생각이 들었다.
4. 입력에 같은 숫자가 있는 경우
3, 4번에 대한 언급은 따로 없어서, 3번은 0인 것만 +1, 4번은 그냥 무시(숫자를 중복으로 입력하지 않는다는 조건)하기로 했다.
🌐 # 코드 3
def make_lotto_number(string):
string_list = list(string)
number_list = []
num = 0
for i in range(6):
max = -1
num = string_list[i] % 46
if (num > 45 or num < 1):
num = 1
# print('num: ', num, '------------------------------------')
# 중복 제거
if num in number_list:
idx = number_list.index(num)
if(string[idx] > string[i]): max = idx
else: max = i
if (num > 45 or num < 1):
num = 1
number_list.append(num)
# print('전:', number_list[-1])
if(max > -1):
# print('max: ', max)
number_list[max] = number_list[max] + 1
# print('후:', number_list[max])
print('number_list: ', number_list, '=======================')
return number_list
# 1 : 4151361,13597019,222,123315,4,13516 => [45, 17, 38, 35, 4, 39]
# 2 : 1370519,12970,1,4747475758,8079013768590167835917,22 => [41, 44, 1, 34, 25, 22]
# 3 : 17239407190457, 178278, 1111, 14595971035597, 33, 55 => [31, 28, 7, 8, 33, 9]
input_num = list(map(int, input().split(',')))
print(make_lotto_number(input_num))
원래는 중복 제거를 리스트에 넣기 전에 했다.
이렇게 진행하면 리스트에 다 넣고 중복된 값이 존재할 수 있기 때문에, 리스트에 append를 먼저 한 후 중복 제거를 실시하는 방식으로 코드를 바꿨다.
🌐 # 코드 4
def make_lotto_number(string):
string_list = list(string)
number_list = []
num = 0
for i in range(6):
num = string_list[i] % 46
if (num > 45 or num < 1): num = 1
number_list.append(num)
# 중복 제거
for i in range(6):
max = -1
for n in range(i):
if(number_list[i] == number_list[n]):
if(string_list[i] > string_list[n]): max = i
else: max = n
number_list[max] = number_list[max] + 1
print('number_list: ', number_list, '=======================')
return number_list
# 1 : 4151361,13597019,222,123315,4,13516 => [45, 17, 38, 35, 4, 39]
# 2 : 1370519,12970,1,4747475758,8079013768590167835917,22 => [41, 44, 1, 34, 25, 22]
# 3 : 17239407190457, 178278, 1111, 14595971035597, 33, 55 => [31, 28, 7, 8, 33, 9]
input_num = list(map(int, input().split(',')))
print(make_lotto_number(input_num))
코드 3의 경우 원하는대로 출력되지 않는다는 문제점이 있었다.
입력 : 1, 2, 3, 45, 46, 47
출력 : [1, 2, 3, 45, 0, 1]
1. 46 점검 시 : <1, 2, 3, 45, 1> → <1, 2, 3, 45, 2> → <1, 2, 3, 45, 3> → <1, 2, 3, 45, 4>
2. 47 점검 시 : <1, 2, 3, 45, 4, 1> → <1, 2, 3, 45, 4, 2> → <1, 2, 3, 45, 4, 3> → <1, 2, 3, 45, 4, 4> → <1, 2, 3, 45, 4, 5>
위의 과정으로 진행되도록 코드를 바꾸니(코드 4) 원하는대로 출력이 잘 되는 것을 확인했다.
하지만 또 딜레마에 빠졌다.
- 1, 2, 3, 45, 91, 137 실행 결과 [1, 2, 3, 45, 1, 2]가 출력된다.
number_list[max] = number_list[max] + 1한 값(리스트 내에서 중복제거하는 과정에서 +1을 했을 때)이 45를 넘는다면 1로 초기화된다. 만약 이게 또 안에 있는 값이랑 겹친다면?
무한 굴레(리스트에 중복되는 값이 없는게 확인 될 때까지 점검)라는 생각이 들었다.
솔직히 말하자면 코드에 for문, if문이 너무 많아서 복잡해 보일 것 같았고, 과제한 다른 사람들한테 물어보니 위의 실행 예시 3개만 맞게 나오는거 확인되면 제출했다고 했다. 별 다른 반례를 생각 안 했다고...
그래서 나도 토요일에 강사님이 풀어주시는 코드를 보기로 하고 그냥 제출했다.
🌐 강사님의 코드
def make_lotto_number(string):
"""
input 함수를 통해 입력받은 변수를 string이라는 parameter로 넘겨줍니다.
해당 string을 처리하여 6개의 1 ~ 45 사이의 숫자를 가지는 리스트를 만들어서 return 합니다.
"""
raw_numbers = [int(x) for x in string.split(',')]
# number_list = [(x % 45) + 1 for x in raw_numbers] # 1 ~ 45
number_list = [x % 46 for x in raw_numbers] # 0 ~ 45
# 46의 배수인 숫자들은 0으로 변환이 되기 때문에, 0인 숫자들은 45로 변환.
for idx in range(len(number_list)):
if number_list[idx] == 0:
number_list[idx] = 45
# 중복 숫자 처리하기
# --> 중복인 숫자 2개가 원래 가지고 있던 숫자를 비교해서 큰 값이었던 위치에 있는 숫자를 +1 한다.
# brute-force(전탐색)
for i in range(len(number_list)): # i = 1
for j in range(i+1, len(number_list)): # j = 2, 3, 4, 5
while number_list[i] == number_list[j]: # 2개 숫자가 모두 다를때 까지,
if raw_numbers[i] > raw_numbers[j]:
if number_list[i] != 45:
number_list[i] = number_list[i] + 1
else: # number_list[i] == 45면, 46이 되기 때문에 1로 변환.
number_list[i] = 1
else: # raw_numbers[i] <= raw_numbers[j]
if number_list[j] != 45:
number_list[j] = number_list[j] + 1
else:
number_list[j] = 1
return number_list
input_numbers = input() ## 사용자 입력(stdin)을 받아서 문자열로 저장.
number_list = make_lotto_number(input_numbers) ## 처리가 다된 숫자 6개가 담긴 리스트를 전달받음.
print(number_list)
강사님께서 반례가 존재하는 것을 알고, 문제를 조금 고쳐오셨다.
- 입력에 중복된 값이 존재하면, 앞에 있는 값에 +1
하지만, 여전히 내가 해결하지 못한 위의 문제에 대해서는 이 코드도 마찬가지였다.
- 1, 2, 3, 45, 91, 137 실행 결과 [1, 2, 3, 45, 1, 2]가 출력된다.
마지막 남은 10분 QnA 시간에 질문드렸는데, 강사님께서 이 문제가 아예 잘못된 것일수도 있겠다고 조금 더 고민해보고 알려주신다고 했다.
문제를 처음 읽을 때부터 어떻게 코드를 짜야할 지 대강은 잡혔지만, 세세하게 잡히지는 않았다.(위에서 언급한) 내가 고민했던 여러 예외들이 존재했기 때문이다. 다른 사람들처럼 '실행 결과만 잘 나오면 됐지'라는 생각에서 그치지 않고, 2시간 정도 고민해보는 시간을 가졌던 게 나름 값졌다고 생각한다. 만약 마지막 반례를 찾아내지 못했다면, 강사님도 옳은 코드라고 생각하셨을 것이니... 오랜만에 알고리즘 코드 짜면서 생각해보니 나름 흥미로웠다. 열심히 해야지 🔥
'🎈 활동 > 🎁 CJ 리모트 인턴십' 카테고리의 다른 글
[소개] CJ 리모트 인턴십(Remote Internship)이 뭐야..? (0) | 2023.10.14 |
---|