본문 바로가기

Algorithm/KaKao

2020 카카오 인턴십 - 키패드 누르기

난이도 level1 문제

 

programmers.co.kr/learn/courses/30/lessons/67256

 

코딩테스트 연습 - 키패드 누르기

[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"

programmers.co.kr

 

 

키패드누르기

 

 

 

 

이 문제에서 나는 서로다른 위치의 키패드의 이동 거리를 계산 할 수 있다면 문제를 쉽게 풀 수 있을 것 같아서

패턴을 찾기 시작했고 아래와 같은 패턴을 찾게됐다.

 

숫자 5에서 상하좌우 로 이동시 

 

상 : -3,  하 : +3

좌 : -1,  우 : 1

 

모든 위치에서 상하좌우로 움직일 때 이동 할 곳이 있다면 위의 패턴이 동일하게 적용 되는 걸 확인 할 수 있다.

그렇다면 상하는 +-3   좌우는 +-1   이기 때문에  절대값로 보면  상하 : 3 ,  좌우: 1  로 볼 수 있다

이제 실제로 거리를 구하는데 적용해 보자!!

 

우선 이동할 위치를 X라고 하고 도착지를 Y로한다.

1. X-Y 의 절대값을 씌운다.

2. 절대값에서 상or하 로 이동할 수 있는 거리만큼 이동한다

   (참고로 상하는 3씩 이동한다.)

3. 더이상 상하로 이동할 수 없다면 좌우로 이동한다

   (좌우는 1씩 이동한다.)

 

상하이동거리 = | X - Y | / 3

좌우이동거리 = | X - Y | % 3  

총 이동거리 =  ( | X - Y | / 3 ) + ( | X - Y | % 3 )  

 

실제로 값을 대입해 보자

X=1, Y=8

 

상하이동거리 = | 1 - 8 | / 3 = 2

좌우이동거리 = | 1 - 8 | % 3 = 1

총거리 = 상하이동거리 + 좌우이동거리 = 3

                   

이제 패턴을 찾았기 때문에 우리는 문제를 매우 쉽게 풀 수 있다.

 

 

 

public class PressKeypad {
    public static void main(String[] args) throws Exception {
        
        int [] numbers1 = {1,3,4,5,8,2,1,4,5,9,5};
        int [] numbers2 = {7,0,8,2,8,3,1,5,7,6,2};
        int [] numbers3 = {1,2,3,4,5,6,7,8,9,0};


        PressKeypad app = new PressKeypad();
        System.out.println(app.solution(numbers1,"right"));

    }

    /*  T = 타겟, L = 왼손엄지, R = 오른손엄지
     *  
     *  1. T가 2,5,8,9 에 속하지 않으면 L과 R의 기본 선택번호화 순서대로 비교해서 터치
     *  2. T가 2,5,8,9 에 속하면 왼손거리 =  ( (|L-T|)/3 ) + ( (|L-T|)%3 )  
     *                       오른손거리 =  ( (|R-T|)/3 ) + ( (|R-T|)%3 )
     *                   를 각각 구한다.      
     *  3. 만약 T가 0이라면 11로 변환해서 값을 구한다.
     *  4. 구한 거리의 크기가 같으면 우선순위 손으로 터치하고 터치 한 손의 위치를 변경한다.
     *  5. 구한 거리의 크기가 다르면 가까운 손으로 터치하고 터치 한 손의 위치를 변경한다.
    */
    
    
    static int leftLocation    = 10;                           // 왼손의 위치
    static int rightLocation   = 12;                           // 오른손의 위치
    
    public String solution(int[] numbers, String hand) {
        
        int [] leftArea     = {1,4,7};                         // 왼쪽 영역숫자
        int [] targetList   = {2,5,8,0};                       // 경쟁영역 숫자 
        String defaultHand  = "left".equals(hand) ? "L" : "R"; // 기본으로 들어오는 손 변경저장
        StringBuffer result = new StringBuffer();              // 결과 버퍼
        
        int leftOrRight    = 0;                                // 왼손거리 - 오른손거리
        int targetTemp     = 0;                                // 터치 해야되는 숫자 

        
        for(int target : numbers) {
            
            if(isEasyChoice(target,targetList)) {              // 경쟁영역의 숫자가 아닌 경우
                pressEasyChoice(target,leftArea,result);       // 간단 버튼클릭 수행
            } else {                                           // 경쟁영역의 숫자인 경우                    
                targetTemp = (target == 0) ? 11 : target;      
                leftOrRight   = getDistance(leftLocation,targetTemp) - getDistance(rightLocation,targetTemp);
                pressHardChoice(leftOrRight,targetTemp,defaultHand,result);  // 경쟁영역의 숫자 버튼클릭 수행
            }   
        }
        return result.toString();
    }
    
    
    // 간단 버튼클릭 수행
    public void pressEasyChoice(int target, int [] leftArea, StringBuffer result) {
        if(isLeftTouch(target,leftArea)) {  // 왼손으로 터치
            result.append("L");
            leftLocation = target;
        } else {                            // 오른손으로 터치
            result.append("R");
            rightLocation = target;
        }
    }
    
    // 거리계산 후 버튼클릭
    public void pressHardChoice(int leftOrRight, int targetTemp,String defaultHand,StringBuffer result) {
        if(leftOrRight == 0) {
            result.append(defaultHand);

            if("L".equals(defaultHand)) {
                leftLocation = targetTemp;
            } else {
                rightLocation = targetTemp;
            }

        } else if(leftOrRight < 0) {
            result.append("L");
            leftLocation = targetTemp;
        } else {
            result.append("R");
            rightLocation = targetTemp;   
        }   
    }
    
    // 왼손에 해당 되는지 영역인지 체크한다.
    public boolean isLeftTouch(int compareNum , int [] leftArea) {
        for(int target : leftArea) {
            if(target == compareNum) return true;
        }
        return false;
    }
    
    
    // 거리 검사가 필요한지 체크한다.
    public boolean isEasyChoice(int compareNum, int[] targetList) {
        for(int target : targetList) {
            if(target == compareNum) return false;
        }
        return true;
    }
    
    // 두 숫자의 이동 거리를 계산한다.
    // 두 point의 거리 = ( (|L-T|)/3 ) + ( (|L-T|)%3 )
    public int getDistance(int point, int target) {
        int subStracAbsNum = Math.abs(point - target);
        return (subStracAbsNum/3) + (subStracAbsNum%3);
    }
    
}