본문 바로가기
파이썬/코딩테스트

[파이썬] 코딩테스트 03 구현_ 카카오_키패드 누르기

by nemonemonemo 2025. 8. 5.

문제

https://school.programmers.co.kr/learn/courses/30/lessons/67256?language=python3

문제 설명

스마트폰 전화 키패드의 각 칸에 다음과 같이 숫자들이 적혀 있습니다.

이 전화 키패드에서 왼손과 오른손의 엄지손가락만을 이용해서 숫자만을 입력하려고 합니다.

맨 처음 왼손 엄지손가락은 * 키패드에 오른손 엄지손가락은 # 키패드 위치에서 시작하며, 엄지손가락을 사용하는 규칙은 다음과 같습니다.

  1. 엄지손가락은 상하좌우 4가지 방향으로만 이동할 수 있으며 키패드 이동 한 칸은 거리로 1에 해당합니다.
  2. 왼쪽 열의 3개의 숫자 1, 4, 7을 입력할 때는 왼손 엄지손가락을 사용합니다.
  3. 오른쪽 열의 3개의 숫자 3, 6, 9를 입력할 때는 오른손 엄지손가락을 사용합니다.
  4. 가운데 열의 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 해주세요.

입출력 예

numbers hand result

[1, 3, 4, 5, 8, 2, 1, 4, 5, 9, 5] "right" "LRLLLRLLRRL"
[7, 0, 8, 2, 8, 3, 1, 5, 7, 6, 2] "left" "LRLLRRLLLRR"
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0] "right" "LLRLLRLLRL"

입출력 예에 대한 설명

입출력 예 #1

순서대로 눌러야 할 번호가 [1, 3, 4, 5, 8, 2, 1, 4, 5, 9, 5]이고, 오른손잡이입니다.

왼손 위치 오른손 위치 눌러야 할 숫자 사용한 손 설명

* # 1 L 1은 왼손으로 누릅니다.
1 # 3 R 3은 오른손으로 누릅니다.
1 3 4 L 4는 왼손으로 누릅니다.
4 3 5 L 왼손 거리는 1, 오른손 거리는 2이므로 왼손으로 5를 누릅니다.
5 3 8 L 왼손 거리는 1, 오른손 거리는 3이므로 왼손으로 8을 누릅니다.
8 3 2 R 왼손 거리는 2, 오른손 거리는 1이므로 오른손으로 2를 누릅니다.
8 2 1 L 1은 왼손으로 누릅니다.
1 2 4 L 4는 왼손으로 누릅니다.
4 2 5 R 왼손 거리와 오른손 거리가 1로 같으므로, 오른손으로 5를 누릅니다.
4 5 9 R 9는 오른손으로 누릅니다.
4 9 5 L 왼손 거리는 1, 오른손 거리는 2이므로 왼손으로 5를 누릅니다.
5 9 - -  

따라서 "LRLLLRLLRRL"를 return 합니다.

입출력 예 #2

왼손잡이가 [7, 0, 8, 2, 8, 3, 1, 5, 7, 6, 2]를 순서대로 누르면 사용한 손은 "LRLLRRLLLRR"이 됩니다.

입출력 예 #3

오른손잡이가 [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]를 순서대로 누르면 사용한 손은 "LLRLLRLLRL"이 됩니다.


풀이

  • 문제 이해를 위한 정리
    • 엄지 손가락만 사용한다 (오른손 엄지/왼손 엄지)
    • 초기 위치: L (*), R(#)
    • 이동경우 : LRUD → 대각선은 움직임이 X ⇒ 수직과 수평으로만 따짐
    • 버튼 동작의 룰 case by case → if문 사용하겠네
      • 1, 4, 7 : 무조건 왼손
      • 3, 6, 9 : 무조건 오른손
      • 2, 5, 8, 0 : 가장 가까운 거리 → 거리 계산 (자주 사용되겠다)
        • 거리가 같을 때
          • 입력의 어느 손 잡이냐가 중요 → hand 정보 필요
        • 거리가 다를 때
          • 거리가 짧은 것을 선택
    • solution 함수 제출
    • 입력
      • numbers
        • 누를 숫자 리스트 [1, 3, 4, 5, 8, 2, 1, 4, 5, 9, 5]
        • 0~9 정수만 딱 들어옴
        • 갯수는 1~1000개
      • hand
        • 어느손잡이(문자열)→ “left”, “right”
    • 출력
      • answer
        • 문자열
        • 입력 number에 해당하는 버튼 누른 손(L/R)+ 공백없이 문자열!
  • 이슈
    • 핸드폰 키패드를 어떻게 코드화할 것인가
    • 코드화 + 자표화가 관건

  • 거리: 직교거리(가로거리 얼마 + 세로 거리 얼마)
    • 대각선 거리를 계산하지 않음
    • 가로 거리의 차이 + 세로 거리의 차이
    • 2개의 버튼 사이의 거리 빈번하게 계산 (여러번 사용될 것… ) → 1개의 case에서도 여러 번 활용이 필요해서 ⇒ 함수로 만들어보자
    • 개인의 선택 → 2개의 버튼 사이의 거리(직교 거리) 계산하는 함수 만들 것
  • 세팅
    • 위치 & 거리 계산
      • 키패드 추상적인 부분에 대한 코드화 : 좌표화!!!!!
        • 주어진 키패드에 코드화 → 좌표, dict
          • 초기값 *, #를 포함해서 입력으로 숫자 0 ~ 9 모든 버튼이 대상
          • 키값들을 문자열로, 값(위에 설정한 좌표값) ⇒ 완전히 개인의 취향(좌표 다르게 잡아도 됨)
          • 핵심 키패드라는 것을 코드화 하는 것
            #키패드 딕셔너리로 코드화
            key_pad = {
                "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],
                "*":[3,0], "0":[3,1], "#":[3,2],
            }
            key_pad
            ​
          • 참고) 앞에서처럼 리스트 중심으로 정수 인덱스를 기반으로 한다면
            # 키패드 리스트로 정수인덱스 활용해 코드화
            # 참고) 앞에서처럼 리스트 중심으로 정수 인덱스를 기반으로 한다면
            
            key_pad_list = ["1","2","3","4".....]
            pos_x        = [ 0, 0,   0, 1,......]
            pos_y        = [0,   1,   2,0,,,,,,,]
            pos          = [ [0,0], [0,1], [0,2], [1,0].,,,, ]
            
            ​

  • 예) * 위치에 있을 때 좌표값은?
    key_pad["*"][0], key_pad["*"][1]
    
    #멀티 할당 사용 가능
    temp_x, temp_y = key_pad["*"]
    print(temp_x, temp_y)
    ​
  • 코드의 흐름 → 가장 큰 틀 : 누를 버튼은 롤링하는 것
    for num in numbers:
    	if 1/4/7:
    		무조건 왼손
    	elif 3/6/9:
    		무조건 오른손
    	else/elif 2/5/8/0:
    		양 손에서 이 버튼 사이의 거리 계산
    		# 함수로 할 것
    		(입력 : 손의 위치,누를 버튼) --> 출력 : 수직거리
         D_L( 왼손 거리), D_R(오른손 거리)
         if 거리가 다를 떄:
    	     짧은 거리의 손을 선택!!!
    	    else: #거리 같을 때
    		    입력변수 hand를 참조해서 사용
    
    ​
  • 추가적인 기능: 거리 구하는 부분 —> 여러번 사용될 것 같아서 함수로 만들 것
    • 2, 5, 8, 0 일 때만 불러서 사용하면 됨

    • 입력: 2개 키패드 위치(눌러야할 키패드, 손 위치)
    • 기능: 입력 2개 위치상 거리 (직선거리, L2, 맨하탄 거리 etc) 계산
    • 출력: 계산 결과

    • 1-2, 2-1 : 어떤 숫자이든 다 양수로 나와야함
      • 음수여도 최종적으로 양수가 나와야 ⇒ 절대값 사용!
      • abs() 함수 사용해도 된다.
        #거리 구하는 부분 —> 여러번 사용될 것 같아서 함수로 만들 것
        def get_distance(number, pos):
        	# 입력으로 받은 number, pos 변수 : 이 함수 내에서만 생존!!!
          key_pad = {"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],"*":[3,0], "0":[3,1], "#":[3,2],}
        	
        	#명시적으로 눌러야 할 버튼, 위치 버튼 : 문자열로 형 변환
        	number = str(number)
        	pos = str (pos)
        	
          # 1) 눌러야 할 버튼의 좌표값 & 파이썬 멀티 할당
          x_number, y_number = key_pad[number]
          # 2) 손의 위치 버튼의 좌표값 & 파이썬 멀티 할당
          x_pos, y_pos = key_pad[pos]
          #3) 1번하고 2번하고 수직 거리 : abs/ if/......
          abs_dis = abs(x_number - x_pos) + abs(y_number-y_pos)
        
          # 최종 출력!!!!
          return abs_dis
        ​

 

def get_distance(number, pos):
    key_pad = {"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],"*":[3,0], "0":[3,1], "#":[3,2],}
    number = str(number)
    pos = str(pos)
    x_number, y_number = key_pad[number]
    x_pos, y_pos = key_pad[pos]
    abs_dis = abs(x_number - x_pos) + abs(y_number-y_pos)
    return abs_dis

def solution(numbers, hand):
    answer = ''
    #------------------------------
    # 1-1) 필요한 변수들에대한 세팅 : 초기화!!!
    left_pos = "*"
    right_pos ="#"
    # 1-2) 필요한 변수 세팅 
    #     : 무슨손 잡이인지 left/right으로 입력 -> 이걸 L/R로 사용해야함
    if hand =="left":
	    hand = "L"
    else: # --> 오른손 잡이...
	    hand = "R"
    #------------------------------
    # 2) 본격적인 할 일 : 눌러야할 버튼 롤링!!!
    for num in numbers:
        # 2-1) 무조건 왼손 : 1/4/7
        if num in [1,4,7]: #if (num ==1) or (num==4) or (num==7):
            answer += "L"
            # ++ 왼손으로 눌렀으니,,왼손 위치 갱신!!!!
            left_pos = num
        # 2-2) 무조건 오른손 : 3/6/9
        elif num in [3,6,9]:
            answer += "R"
            # +++ 오른손을 눌렀으니,,,오른손의 위치 갱신!!
            right_pos = num
        # 2-3) 중간 따지자 : 2/5/8/0
        #else/elif
        elif num in [2,5,8,0]:
            # 각 손과 num사이의 거리 계산!!!!! --> 비교!!!:담당할 변수 만들자.
            dis_left = get_distance(num, left_pos)
            dis_right = get_distance(num, right_pos)
            # 2-3-1) 거리가 왼쪽이 짧을 떄
            if dis_left < dis_right:
                answer += "L"
                left_pos = num
            # 2-3-2) 거리가 오른쪽이 짧을 때
            elif dis_left > dis_right:
                answer += "R"
                right_pos = num
            # 2-3-3) 거리가 동일할 때!
            elif dis_left == dis_right:
                answer += hand
                # 위치를 갱신을 해야하는데,,,무슨 손 잡이냐에 따라서,,,
                if hand =="R":
                    right_pos = num
                elif hand =="L":
                    left_pos = num

    #------------------------------
    
    return answer