TIL / 5/2 / 프로그래머스 - 크레인 인형뽑기게임
문제
https://school.programmers.co.kr/learn/courses/30/lessons/64061

시도
먼저 복잡해보이는 문제일수록.. 해설처럼 예상도를 그려본 뒤 풀어보는 것이 좋기 때문에 매번 그랬던 것 처럼 입력 예제와 answer값에 맞는 예상도를 그려놨다.
# 입력 예제
board = [[0,0,0,0,0],[0,0,1,0,3],[0,2,5,0,1],[4,2,4,4,2],[3,5,1,3,1]]
moves = [1,5,3,5,1,2,1,4]
# answer = 4
# 예상도
# 4
# >moves> 2
# 0 0 0 0 0 3 <
# 0 0 1 0 3 1 <
# 0 2 5 0 1 1 <
# 4 2 4 4 2 3 <
# 3 5 1 3 1 4
처음엔 board의 배열 순서가 잘 이해되지 않았는데.. 그려놓고 보니
2차원 배열의 뒤에서부터 제일 아래에 깔린다는 것을 알게되었다.
먼저 moves를 적용한 후의 리스트를 구해서 append로 들어오는 원소 중 바로 앞 원소와 중복되는 것이 있으면 카운트를 세고 지워버리는 형식의 조건문을 적으면 될 것 같았다.
그리고 moves를 적용한 후의 리스트를 구하는 방법을 생각해보았다.
이런 식으로 answer를 도출하는데 무엇이 필요한지 거꾸로부터 거슬러 올라가면 좀 더 생각하는 것이 쉬워지는 것 같다.
def solution(board, moves):
a_list = []
answer = 0
for crane in moves:
# board의 배열이 하나 씩 순차대로 box에 들어간다
for box in board:
# item = board[0][0] // 예제라면 첫 바퀴에 이런 식으로 돌아가게 된다. box[crane-1]과 같다.
item = box[crane-1]
# 0은 없다는 것을 의미하므로 0번째 인덱스자리에서 0이 아닌 숫자를 찾게 된다면
if item != 0:
# 빈 리스트에 넣기
a_list.append(item)
# append후 픽업한 item은 0으로 만들어준다.
box[crane-1]=0
break
# a_list의 길이가 1과 같다면 pass, out of index가 뜨기 때문에
if len(a_list) == 1:
pass
# a_list의 최근에 들어온 원소가 바로 앞 원소와 같다면
elif a_list[-1] == a_list[-2]:
# answer에 +=2를 카운트
answer += 2
# a_list에 붙어있던 중복된 숫자 두 개를 제거
del(a_list[-1],a_list[-1])
return answer
하지만 위 식은.. 총 채점 테스트 케이스에서 2개의 런타임에러가 나버리고..
다시 생각해봤을 땐 아마 moves의 총 리스트를 한꺼번에 구해놓은게 문제가 아니였을까 싶었다.
이렇게 return값이 '없어진 인형의 갯수'같이 특이한 문제들은 굳이 문제 전체를 풀지 않아도
일부분, 핵심만 관통하면 되는 문제들도 많았기 때문에.. 이번에도 바보 짓을 한 건가 싶었다.
해결
팀원 분의 식을 보고 내 식의 문제점을 깨달았다!
# ----- 팀원 분 식 -----
def solution(board, moves):
answer = 0
stack = []
for move in moves:
for N in range(len(board)):
# x = 뽑은 인형의 번호
x = board[N][move - 1]
if x != 0:
board[N][move - 1] = 0
# ----- !!!!! -----
if stack and stack[-1] == x:
stack.pop(-1)
answer += 2
else:
stack.append(x)
break
return answer
처음엔 왜 if문에 리스트 전체(stack)를 불러오신거지..? and..? 저게 뭐지..? 하고 전혀 이해가 가지 않았다.
저 if문을 이해하지 못하니 첫 바퀴에는 분명 빈 리스트에 [-1]이라는 인덱스를 세고있는데도 왜 out of range가 뜨지 않는지도 이해를 못했었다.
# x = 뽑은 인형의 번호
x = board[N][move - 1]
# 인형이 있다면(0이 아니라면)
if x != 0:
# 0으로 원소의 값을 변경하기
board[N][move - 1] = 0
# 만약 stack과 stack[-1]이 x와 같다면
if stack and stack[-1] == x:
# stack에서 -1을 pop
stack.pop(-1)
# answer에 +2를 카운트
answer += 2
# 그 외 : stack리스트에 x원소 넣기
else:
stack.append(x)
# !! 중요 !! break가 없다면 for문이 계속 돌아가게 된다.
break
return answer
if문에 and조건을 달아줌으로 stack에도 인덱스가 있어야 if문으로 진입할 수 있고,
그 전엔 전부 else문으로 빠지게 되어 자동으로 stack 리스트에 append로 들어가게 되는 것 이였다!
배운 점
나도 out of range 때문에 마지막 if문에서 고민을 좀 오래 했었는데 저런 방법이 있는 줄은 몰랐다.
if문에 전체리스트 and 조건을 달아서 out of range 오류를 피할 수 있다니.. 조금 충격이였다.. 처음에 원소를 먼저 0으로 바꿔준다는 것도 충격이였지만 어차피 내가 꺼낸 인형은 팀원 분의 식에서는 X, 내 식에서는 item이라는 변수에 담아놓은 상태이니 별다를 점이 없는 것이였다.
그리고 똑같이 식을 쓰고 딱 하나 달라서 틀렸던게 있었는데 원래는 del함수를 썼었다.
그런데 pop과는 확실히 다른지 결과값이 다르게 나오며.. del, pop, remove.. 다 지우는 함수인데 뭐가 이렇게 많을까 :>
오늘도 팀원 분들 덕분에 많은 걸 알아간다... 감사합니당 :p !!!
나만의 작은 꼬북튜터님 TDMI.. To Day Much Information..
죄송합니다 튜터님과 튜터님의 TDMI를 기다리는 여러분...(0명)
한동안 TIL와 싸워서 사이가 너무 안좋았습니다 오늘 화해했습니다 :p..
뭐 쓰지... 튜터님이 모자라... 으으..
튜터님은 가끔 약지에 반지를 끼고 강의를 하신다.. 처음엔 결혼하신 줄 알았다..
튜터님은 여자친구가 있으시다.. 두 분이 같이 귀여우시다... 어떡해...
물론 스토커는 아니고 커피와 함께 받은 전화번호로 훔쳐보았다.. 한 번 더 감사합니다 튜터님..