문제
스마트폰 전화 키패드의 각 칸에 다음과 같이 숫자들이 적혀 있습니다.
이 전화 키패드에서 왼손과 오른손의 엄지손가락만을 이용해서 숫자만을 입력하려고 합니다.
맨 처음 왼손 엄지손가락은 * 키패드에 오른손 엄지손가락은 # 키패드 위치에서 시작하며, 엄지손가락을 사용하는 규칙은 다음과 같습니다.
- 엄지손가락은 상하좌우 4가지 방향으로만 이동할 수 있으며 키패드 이동 한 칸은 거리로 1에 해당합니다.
- 왼쪽 열의 3개의 숫자 1, 4, 7을 입력할 때는 왼손 엄지손가락을 사용합니다.
- 오른쪽 열의 3개의 숫자 3, 6, 9를 입력할 때는 오른손 엄지손가락을 사용합니다.
- 가운데 열의 4개의 숫자 2, 5, 8, 0을 입력할 때는 두 엄지손가락의 현재 키패드의 위치에서 더 가까운 엄지손가락을 사용합니다.
4-1. 만약 두 엄지손가락의 거리가 같다면, 오른손잡이는 오른손 엄지손가락, 왼손잡이는 왼손 엄지손가락을 사용합니다.
순서대로 누를 번호가 담긴 배열 numbers, 왼손잡이인지 오른손잡이인 지를 나타내는 문자열 hand가 매개변수로 주어질 때, 각 번호를 누른 엄지손가락이 왼손인 지 오른손인 지를 나타내는 연속된 문자열 형태로 return 하도록 solution 함수를 완성해주세요.
[제한사항]
- numbers 배열의 크기는 1 이상 1,000 이하입니다.
- numbers 배열 원소의 값은 0 이상 9 이하인 정수입니다.
- hand는 "left" 또는 "right" 입니다.
- "left"는 왼손잡이, "right"는 오른손잡이를 의미합니다.
- 왼손 엄지손가락을 사용한 경우는 L, 오른손 엄지손가락을 사용한 경우는 R을 순서대로 이어붙여 문자열 형태로 return 해주세요.
예전 풀이
생각
無
코드를 어떻게 짜야 할지 전혀 생각이 안 나서 아예 건너 뛰었음
코드
無
다시 생각해보기
생각
result = {}
left = [1, 4, 7]
right = [3, 6, 9]
numbers 배열을 돌며
i가 left에 포함될 경우 경우 result[i]에 L을
i가 right에 포함될 경우 result[i]에 R을 넣는다
그 외에는
마지막 왼손과 마지막 오른손 버튼을 구한다.
그 버튼으로부터 i의 거리를 구해야하는데... 이걸 어떻게 구해야할지
대각선 이동은 불가하고 상하좌우 1칸씩만 이동 가능한건데
그렇게해서 더 가까운 것으로 고르고
둘의 거리가 같다면 어느 손 잡이인지에 의해 정하면 되는데
거리 구하는 걸 어떻게 구현해야할지 모르겠다.
코드
def solution(numbers, hand):
answer = ''
result = {}
left = [1, 4, 7]
right = [3, 6, 9]
for i in numbers:
if i in left:
result[i] = 'L'
elif i in right:
result[i] = 'R'
else:
return answer
- else 파트 구현 못 함
다른 사람 풀이
def solution(numbers, hand):
answer = ''
# 각 버튼별 위치
button_position = [[3, 1], [0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]]
# 왼손 초기 위치
left = [3, 0]
# 오른손 초기 위치
right = [3, 2]
def set_left(number):
nonlocal answer, left
left = button_position[number]
answer = answer + 'L'
def set_right(number):
nonlocal answer, right
right = button_position[number]
answer = answer + 'R'
for number in numbers:
# 왼쪽버튼 처리
if number in [1, 4, 7]:
set_left(number)
# 오른쪽 버튼 처리
elif number in [3, 6, 9]:
set_right(number)
# 가운데 버튼이라면
else:
# 왼손과 오른손의 거리 계산하기
left_distance = abs(left[0] - button_position[number][0]) + abs(left[1] - button_position[number][1])
right_distance = abs(right[0] - button_position[number][0]) + abs(right[1] - button_position[number][1])
# 거리가 같다면
if left_distance == right_distance:
# 오른손잡이 일때
if hand == 'right':
set_right(number)
# 왼손잡이 일때
else:
set_left(number)
# 왼쪽이 거리가 짧다면
elif left_distance < right_distance:
set_left(number)
# 오른쪽 거리가 짧다면
else:
set_right(number)
# 결과 반환
return answer
if __name__ == "__main__":
numbers_list = [
[1, 3, 4, 5, 8, 2, 1, 4, 5, 9, 5],
[7, 0, 8, 2, 8, 3, 1, 5, 7, 6, 2],
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
]
hand_list = [
"right",
"left",
"right"
]
result_list = [
"LRLLLRLLRRL",
"LRLLRRLLLRR",
"LLRLLRLLRL"
]
length = len(result_list)
for i in range(length):
answer = solution(numbers_list[i], hand_list[i])
if answer == result_list[i]:
print('{}번 정답입니다.'.format(i+1))
else:
print('{}번 실패입니다.'.format(i+1))
print('{} != {}'.format(answer, result_list[i]))
코드 스스로 해석하고 이해하기
- 각 버튼을 (0,0) 부터 (3,2)까지 좌표로 설정했다. 0부터 작성해서 (3,1)이 먼저 나왔다.
- 왼손의 초기 위치 *과 오른손의 초기 위치 #을 설정해준다
- set_left라는 함수를 설정한다
- 왼손으로 숫자를 누를 때 호출된다.
- 누를 숫자를 파라미터로 받아와
** nonlocal **
중첩된 함수 내부에서 외부 함수의 변수를 참조하게 해준다
- Python에서 함수 내부에서는 외부 함수의 변수를 참조(읽기)는 할 수 있지만, 변경(쓰기)는 할 수 없다.
그러나 nonlocal키워드를 사용하면 이런 제한을 무시하고 외부 함수의 변수를 직접 변경할 수 있게 된다.
- 여기서는 set_left 함수 내부에서 외부함수 solution의 answer와 left 변수를 변경하려고 할 때 사용?
- left는 왼손의 현재 위치를 나타내는 리스트이다
- 원래 버튼 위치 나타내는 button_position을 이용하여 왼손의 위치를 눌러야할 숫자의 위치로 이동시킨다
- answer에 L을 추가함으로써 현재 숫자를 왼손으로 눌렀음을 기록한다
- 오른손도 마찬가지로 설정해준다
- 숫자 패드 누르기 = numbers만큼 for문을 돌면서
- 만약 누른 번호가 1, 4, 7 중에 하나라면 set_left 함수로
- 만약 누른 번호가 3, 6, 9 중에 하나라면 set_right함수로
- 만약 나머지 버튼이라면
- 왼손과 오른손 버튼 거리를 계산한다.
- 왼손일 경우 공식은 |왼손x - 버튼x| + |왼손y - 버튼y|
** 맨해튼 거리 **
- 두 점 사이 거리 계산
- 그리드(격자) 형태에서 수평 및 수직 이동만을 허용할 경우 필요한 총 이동 거리
두 점 P1(x1,y1)및 P2(x2,y2)
distance = ∣x1−x2∣+∣y1−y2∣
** abs() **
- 절대값을 반환하는 내장함수
- 만약 두 거리가 같다면 오른손잡이일 때 set_right() 왼손잡이일 때 set_left() 함수로 넘긴다
- 왼손이 더 가까우면 set_left()로
- 오른손이 더 가까우면 set_right()로 넘긴다
- answer를 반환해준다
(나머지는 테스트코드~)
def get_distance(keypad, finger_position, next_number):
next_number_position = keypad[next_number]
distance = abs(finger_position[0] - next_number_position[0]) + abs(finger_position[1] - next_number_position[1])
return distance
def solution(numbers, hand):
result = ''
keypad = {
1: [0, 0], 2: [0, 1], 3: [0, 2],
4: [1, 0], 5: [1, 1], 6: [1, 2],
7: [2, 0], 8: [2, 1], 9: [2, 2],
0: [3, 1]
}
left_finger_numbers = [1, 4, 7]
right_finger_numbers = [3, 6, 9]
center_finger_numbers = [2, 5, 8, 0]
left_finger_position = [3, 0]
right_finger_position = [3, 2]
for number in numbers:
if number in left_finger_numbers:
result += 'L'
left_finger_position = keypad[number]
elif number in right_finger_numbers:
result += 'R'
right_finger_position = keypad[number]
else:
left_finger_distance = get_distance(keypad, left_finger_position, number)
right_finger_distance = get_distance(keypad, right_finger_position, number)
if left_finger_distance > right_finger_distance:
result += 'R'
right_finger_position = keypad[number]
elif left_finger_distance < right_finger_distance:
result += 'L'
left_finger_position = keypad[number]
elif left_finger_distance == right_finger_distance:
result += hand[0].upper()
if hand == 'right':
right_finger_position = keypad[number]
elif hand == 'left':
left_finger_position = keypad[number]
return result
코드 스스로 해석하고 이해하기
- 거리 구하는 함수
- 다음 숫자 위치
- 위 코드처럼 맨해튼 거리로 계산
- 딕셔너리를 통해 각 버튼의 위치를 설정해준다
- 왼손 숫자와 오른손 숫자 그리고 가운데 숫자를 리스트로 지정해준다
- 왼손과 오른손 위치를 시작 위치로 초기화해준다
- numbers를 돌면서
- 만약 번호가 왼손 숫자 리스트 안에 있다면 result에 L을 추가하고 왼손의 위치를 keypad딕셔너리의 해당 번호 위치로 바꾼다
- 오른 손도 마찬가지
- 만약 두 군데 다 포함되지 않는 숫자라면
- 왼손 거리는 거리 구하는 함수에 keypad 딕셔너리와 왼손 위치, 그리고 번호를 넘겨주어 계산한다
- 오른손도 마찬가지
- 오른손 거리가 더 가깝다면 result에 R을 넣어주고 오른손의 위치를 해당 번호로 옮겨준다
- 왼손도 마찬가지
- 만약 두 거리가 같다면
- hand로 들어온 문자열의 첫 번째 요소를 대문자로 만든다. (hand는 'left'나 'right'로 주어짐. 이걸 'L'이나 'R'로 만들겠다는 것)
- 이 바꾼 문자를 result에 추가한다 (여기까지는 그냥 result를 채우기 위한 코드)
- 만약 오른손삽이라면 오른손 위치를 해당 번호의 위치로 바꾸고 왼손이라면 ~ (여기서 손 위치를 바꿈)
너무 어렵다!
어쨌든 포인트는 키패드 포지션 설정!
'Python > 프로그래머스' 카테고리의 다른 글
[프로그래머스 lv.1] 신규 아이디 추천 (건너뛴 문제 다시풀기) (1) | 2023.09.19 |
---|---|
[프로그래머스 lv.1] 3진법 뒤집기 (건너뛴 문제 다시풀기) (0) | 2023.09.18 |
[프로그래머스 lv.1] 크레인 인형뽑기 게임 (건너뛴 문제 다시풀기) (0) | 2023.09.17 |
[프로그래머스 lv.1] 실패율 (건너뛴 문제 다시풀기) (0) | 2023.09.16 |
[프로그래머스 lv.1]다트 게임 (건너뛴 문제 다시풀기) (0) | 2023.09.15 |