개발공부/프로그래머스

[프로그래머스] 코딩테스트 Lv.1 키패드 누르기

장아장 2022. 10. 25. 23:20

Source Code : https://github.com/JangAJang/Algorithm/blob/main/프로그래머스_Lv1/키패드%20누르기/src/Solution.java

 

문제를 확인했을 때, 일반 핸드폰에 있는 키패드와 동일한 상태에서 움직여야 한다고 해서 처음엔 키패드를 배열로 구현할 생각을 했다. 

 

근데 문득 든 생각은, '배열이 아니라 그 버튼의 주소를 저장하면 어떨까?' 였다.

기본적으로 0을 제외한 숫자들을 생각해보면, 그 수를 n이라고 했을 때, 그 수의 좌표는 {x/3, x%3}으로 설정해 보았다. 

1 {0, 1} 2 {0, 2} 3 {1, 0}
4 {1, 1} 5 {1, 2} 6 {2, 0}
7 {2, 1} 8 {2, 2} 9 {3, 0}

이 상태를 그려보았을 때, 조금 상태가 어긋남을 느낀 것이,

우리가 일반적인 2차원 배열을 표현할 때 제일 왼쪽 위의 주소는 {0, 0}이다. 

 

그래서 x로 불러와 좌표를 설정할 때, 값을 1씩 빼보았다. 

주소를 구할때 { (x-1)/3, (x-1)%3}로 계산을 했을 때 아래처럼 주소가 나왔다. 

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}

정확히 2차원 배열로 나오고, 여기에 0과 *, #을 추가해야 한다. * = {3, 0}, 0 = {3, 1}, # = {3, 2}로 나머지를 채웠다. 

 

private class Position{
    int[] location;
    int distance;

    public Position(int[] location, int distance){
        this.location = location;
        this.distance = distance;
    }

    public void setDistance(int x){
        distance = Math.abs(location[0] - x/3) + Math.abs(location[1] - x%3);
    }

    public int getDistance(){
        return distance;
    }

    public void setLocation(int[] x){
        location = x;
    }
}

이런 식으로 위치를 나타내는 클래스를 만들었고, 이를 이용해 Postion형 변수 left, right를 만들었다.

이를 이용한 방식은

  1. 눌러야 되는 키의 값 x가 들어온다. (입력시에는 위에서 말했듯이 x-1로 불러온다)
  2. left, right에 setDistance로 x부터 양손의 거리를 구한다. 
  3. getDistance로 두 손을 비교해 더 가까운 손을 찾아낸다. 
  4. 더 가까운 손에 setLocation해준다. (이 때 좌표는 2차원 배열이므로 두 변수를 배열 하나로 담아 저장시킨다. 

이렇게 손이 얼마나 멀리있는지, 어떻게 움직이는지를 구현했다. 

 

다음으로는 이 손들이 움직인다는 것을 어떻게 판단할지를 생각했다. 

  1. 0이 들어오면 11로 만들어준다.
  2. 만약 x%3 == 1이라면 (1, 4, 7) 왼쪽 손이 움직인다
    1. left.setLocation( (x-1)/3, (x-1)%3)
  3. 만약 x%3 == 0이라면 {3, 6, 9) 오른쪽 손이 움직인다
    1. right.setLocation( (x-1)/3, (x-1)%3)
  4. 그게 아니라면 (2, 5, 8, 0) 키패드 중간줄이므로, 거리를 구해서 연산해야 한다.
    1. x로 부터 양손의 거리를 구한다. 
    2. 둘의 거리가 같다면 오른손잡이인지 왼손잡이인지 판단한다
      1. 왼손잡이면 left.setLocation( (x-1)/3, (x-1)%3)
      2. 오른손잡이면 right.setLocation( (x-1)/3, (x-1)%3)

 

이런 과정으로 동작시켰다.

안으로 들여쓰기가 된 부분은 하나의 메서드 안에서 구현할 것이었다면 indent가 엄청났을 것 같다. 

(내가 이걸 생각하는 이유는 https://jangsarchive.tistory.com/17 게시물 참고)

 

~~문 안에 다른 ~~문이 들어가지 않게 하고, 조금 더 보았을 때 이해할 수 있기 위해 메서드를 최대한 세분화 해보았다. 

private String getNextFinger(int x, String hand){
    if(x == 0) x = 11;
    if(x%3 == 1) return setL(x-1);
    if(x%3 == 0) return setR(x-1);
    return findFromMiddleLine(x-1, hand);
}

private String findFromMiddleLine(int x, String hand){
    left.setDistance(x);
    right.setDistance(x);
    if(left.getDistance() == right.getDistance()) return getFromSameDist(x, hand);
    return getFromDifferentDist(x);
}

private String getFromSameDist(int x, String hand){
    if(hand.equals("right")) return setR(x);
    return setL(x);
}

private String getFromDifferentDist(int x){
    if(left.getDistance() < right.getDistance()) return setL(x);
    return setR(x);
}

private String setR(int x){
    right.setLocation(new int[]{x/3, x%3});
    return "R";
}

private String setL(int x){
    left.setLocation(new int[]{x/3, x%3});
    return "L";
}

 

이런 방식으로 문제를 풀었던 것 같다. 

 

배운점

이 문제를 풀기 전에,  백준에서 단계별로 존재하는 2차원 배열의 문제들도 풀어보았다. 

배열과 관련되었다는 문제들을 볼 때 마다 생각하는 것은

  1. 어떻게 하면 그 배열들을 다 담지 않고 끝낼 수 있을까?
  2. 배열을 담아야 한다면 어떻게 담는게 최소화를 시킬 수 있는 방법일까?

라는 것이다. 

 

배열에 데이터를 담는 것 자체가 문제가 되지 않는다. 탐색이나 정렬을 할 때에 배열이나 리스트에 데이터를 담고 시작해야 하니깐.

그렇다면 거기서 얼마나 데이터를 담고, 이를 연산하는 과정을 줄일 수 있을지 생각해보아야겠다.