https://programmers.co.kr/learn/courses/30/lessons/42841
완전 탐색 문제입니다. 어려운 내용은 없지만 문제의 조건을 그냥 지나치기 쉽기 때문에 차근차근 읽어봐야 합니다.
solution 함수의 인자는 baseball이며 길이 1 이상 100 이하의 list 형태입니다.
baseball의 원소는 [세 자리의 수, 스트라이크 수, 볼의 수]이고요. 가능한 모든 숫자에서 세 자리 숫자의 스트라이크와 볼을 만족하는 숫자만을 살리거나, 만족하지 못하는 숫자들을 버리면 쉽게 풀 수 있습니다.
각자 서로 다른 1~9까지 3자리 임의의 숫자를 정한 뒤 서로에게 3자리의 숫자를 불러서 결과를 확인합니다. 그리고 그 결과를 토대로 상대가 정한 숫자를 예상한 뒤 맞힙니다.
각자 서로 다른 수여야 하고, 1~9까지의 범위를 가집니다. 세 자리의 숫자는 100부터 999까지가 가능하겠으나 조건이 있기에 시작은 123, 끝은 987이 되겠네요.
먼저 가능한 숫자들을 전부 골라보겠습니다.
def solution(baseball):
answer = set(str(x) for x in range(100, 1000) if '0' not in str(x)
and str[x][0] != str[x][1] and str[x][1] != str[x][2] and str[x][0] != str[x][2])
조금 식이 길긴 하지만 100부터 999까지의 숫자 중 0을 포함하고 있지 않으며 3자리 숫자가 모두 다른 숫자만이 answer라는 집합의 원소가 됩니다.
for base in baseball:
num, strike, ball = base[0], base[1], base[2]
notAnswer = set()
for ans in list(answer):
strikeBall = game(str(num), str(ans))
if strikeBall[0] != strike or strikeBall[1] != ball:
notAnswer.add(ans)
answer = answer - notAnswer
baseball의 원소 하나하나씩 게임을 진행합니다.
answer는 set이기 때문에 반복문을 돌리기 위해 list형태로 변환시켰고, 반환되는 strikeBall의 첫 번째 원소 strike가 base가 가지고 있는 결과와 맞지 않거나 두 번째 원소 ball이 맞지 않는다면 notAnswer에 포함시킵니다.
한 게임이 끝났을 때 답이 될 수 없는 notAnswer의 원소들을 answer에서 전부 빼면서 answer를 갱신합니다.
def game(compare, ans):
ball, strike = 0, 0
numCountDict = {}
for i in range(3):
if ans[i] == compare[i]:
strike += 1
else:
numCountDict[ans[i]] = numCountDict.get(ans[i], 0) + 1
numCountDict[compare[i]] = numCountDict.get(compare[i], 0) + 1
for key, value in numCountDict.items():
if value > 1:
ball += 1
return [strike, ball]
게임을 진행하는 game 함수입니다. ans와 compare를 비교해 strike 개수와 ball 개수를 return 합니다.
먼저 ans[i]와 compare[i]가 같다면 strike이므로 strike에 1을 더해줍니다.
그렇지 않을 경우에는 numCountDict[해당 숫자]에 1을 더합니다. numCountDict의 value에는 ans와 compare에서 1~9까지의 숫자가 몇 번이나 나왔는지 기록됩니다.
게임이 끝난 후 numCountDict의 value값에서 2번 이상 나온 숫자가 있다면 ball에 1을 더해줍니다. 위치가 다른데 2번 이상 나왔다는 건 ball에 해당하니까요.
마지막으로 solution 함수에서 answer의 길이를 return 해주면 문제는 끝납니다.
전체 Python 코드
def game(compare, ans):
ball, strike = 0, 0
numCountDict = {}
for i in range(3):
if ans[i] == compare[i]:
strike += 1
else:
numCountDict[ans[i]] = numCountDict.get(ans[i], 0) + 1
numCountDict[compare[i]] = numCountDict.get(compare[i], 0) + 1
for key, value in numCountDict.items():
if value > 1:
ball += 1
return [strike, ball]
def solution(baseball):
answer = set(str(x) for x in range(100, 1000) if '0' not in str(x)
and str[x][0] != str[x][1] and str[x][1] != str[x][2] and str[x][0] != str[x][2])
for base in baseball:
num, strike, ball = base[0], base[1], base[2]
notAnswer = set()
for ans in list(answer):
strikeBall = game(str(num), str(ans))
if strikeBall[0] != strike or strikeBall[1] != ball:
notAnswer.add(ans)
answer = answer - notAnswer
return len(answer)
느낀 점
문제의 조건을 더욱 꼼꼼히 읽어야겠습니다. 사전에도 이야기했지만 문제의 조건을 제대로 읽지 않아 그리 어렵지 않은 문제임에도 애를 조금 먹었습니다. 처음에는 "서로 다른" 을 못 봐서 서로 다른 숫자들로만 구성했다가 또 답이 맞지 않아 조건을 다시 보니 1~9까지의 숫자더군요. 저는 0을 포함시키고 있었습니다.
실제 기업 코딩 테스트에서는 테스트 케이스를 그리 많이 주지 않습니다. 보통 3개 정도 주는 것 같고 그 이하로 주는 경우도 봤고요. 테스트 케이스가 없어 정답 확인이 어렵더라도 동작원리에서 누락되는 부분이 없도록 꼼꼼하게 코딩해야겠습니다.
'알고리즘 > 프로그래머스' 카테고리의 다른 글
프로그래머스 - 지형 이동 (0) | 2020.05.21 |
---|---|
프로그래머스 - 네트워크 (0) | 2020.04.06 |
프로그래머스 - 베스트 앨범 (0) | 2020.02.23 |