프론트엔드 개발자의 기록 공간

[프로그래머스 JavaScript] 키패드 누르기 본문

알고리즘_JS/프로그래머스_Level1

[프로그래머스 JavaScript] 키패드 누르기

[리우] 2021. 6. 6. 16:36

프로그래머스 Level1 키패드 누르기 -> 2020 카카오 인턴십 문제

 

문제 설명 : 주어진 입력 numbers에 따라 왼쪽 손가락으로 터치할 것인가 오른쪽 손가락으로 터치할 것인가

선택하면 되는 문제입니다. 조건문은 크게 4가지 경우로 나뉩니다.

1. 1,4,7의 경우 왼쪽 손가락으로만 이용. 

2. 3,6,9의 경우 오른쪽 손가락으로만 이용

3. 가운데일 경우 왼쪽, 오른쪽 손가락에서 가장 가까운 손가락 이용

3-1. 왼쪽 오른쪽이 같은 거리라면 hand로 주어지는 손가락 이용

 

첫번째 풀이

function solution(numbers, hand) {
  var answer = "";
  //초기 왼쪽 손가락 위치 (3,0)
  let Li = 3;
  let Lj = 0;
  //초기 오른쪽 손가락 위치 (3,2)
  let Ri = 3;
  let Rj = 2;

  //키패드 위치 정보 * #은 10 12로 임의로 대체
  let list = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
    [10, 0, 12],
  ];

  //입력 numbers만큼 반복
  for (let k = 0; k < numbers.length; k++) {
    //키패드 2차원 길이만큼 반복
    for (let i = 0; i < list.length; i++) {
      for (let j = 0; j < list[i].length; j++) {
        //입력값과 키패드 위치값이 일치할때
        if (numbers[k] === list[i][j]) {
          //이차원 배열 j값이 0이라면 왼쪽 손가락으로만 사용
          if (j === 0) {
            Li = i;
            Lj = j;
            answer += "L";
            //이차원 배열 j값이 2이라면 오른쪽 손가락으로만 사용
          } else if (j === 2) {
            Ri = i;
            Rj = j;
            answer += "R";
          }
          //가운데 2,5,8,0일 경우
          else {
            //점과 점사이 구하는 공식 이용

            //왼쪽 손가락 위치와 현재 i,j의 떨어진 거리 계산(절대값 이용)
            let tmpL = Math.abs(i - Li) + Math.abs(j - Lj);
            //오른쪽 손가락 위치와 현자 i,j의 떨어진 거리 계산(절대값 이용)
            let tmpR = Math.abs(i - Ri) + Math.abs(j - Rj);

            //떨어진 거리가 더 가까운 경우를 판별해서
            //해당 손가락으로 사용
            if (tmpL > tmpR) {
              Ri = i;
              Rj = j;
              answer += "R";
            } else if (tmpL < tmpR) {
              Li = i;
              Lj = j;
              answer += "L";
              //떨어진 거리가 왼쪽 오른쪽 같은 경우
            } else if (tmpL === tmpR) {
              //왼손잡이라면 왼쪽 이용
              if (hand === "left") {
                Li = i;
                Lj = j;
                answer += "L";
                //오른손잡이일 경우
              } else {
                Ri = i;
                Rj = j;
                answer += "R";
              }
            }
          }
        }
      }
    }
  }
  return answer;
}

코드 설명 : 그래프 좌표값 구하는 방식을 이용해서 풉니다. (Math.abs() 절대값 메소드 사용)

처음에 list배열에 키패드 정보, 왼쪽 손가락 위치, 오른쪽 손가락 위치를 세팅해줍니다.

그 후, 입력으로 주어진 배열 numbers를 반복하면서 list에 해당하는 값을 찾기위해 이중 for문을 탐색해줍니다.

number값과 list에 해당하는 값이 일치하다면 위에 작성한 1,2,3 번째의 조건에 따라 분류해줍니다.

3번째 조건일 경우 가장 가까운 손가락위치를 구하기 위해 마지막에 사용한 왼쪽, 오른쪽 손가락의 좌표값과 현재 i,j의 값을 절대값을 이용하여 빼줍니다. 그 후 위치가 가까운 손가락으로 세팅해줍니다.

왼쪽, 오른쪽이 같다면 hand로 입력해준 손가락을 이용합니다.

 

*초기에 이렇게 작성하여 해결했습니다. 하지만 코드를 보면 가독성도 떨어지고 삼중 for문으로 시간복잡도가 O(n^3)이 되어 비효율적인 코드입니다.

 

 

다른 사람의 풀이를 보고 수정한 두번째 풀이 방법을 소개하겠습니다.

function solution(numbers, hand) {
  var answer = "";
  //객체 배열 이용
  //키패드 위치에 따라 좌표 정보를 세팅
  let list = {
    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],
  };

  //초기 손가락 위치
  let left = list["*"];
  let right = list["#"];

  //입력 numbers만큼 반복
  for (let x of numbers) {
    let [i, j] = list[x]; //입력 숫자위치 i,j에 저장
    //j값이 0이라면 왼쪽 손가락으로만 사용
    if (j === 0) {
      answer += "L";
      left = list[x];
    }
    //j값이 2이라면 오른쪽 손가락으로만 사용
    else if (j === 2) {
      answer += "R";
      right = list[x];
    }
    //가운데일 경우
    else {
      //왼쪽 손가락 위치와 현재 i,j의 떨어진 거리 계산(절대값 이용)
      let tmpL = Math.abs(i - left[0]) + Math.abs(j - left[1]);
      //오른쪽 손가락 위치와 현자 i,j의 떨어진 거리 계산(절대값 이용)
      let tmpR = Math.abs(i - right[0]) + Math.abs(j - right[1]);

      //떨어진 거리가 더 가까운 경우를 판별해서
      //해당 손가락으로 사용
      if (tmpL > tmpR) {
        right = list[x];
        answer += "R";
      } else if (tmpL < tmpR) {
        left = list[x];
        answer += "L";
        //떨어진 거리가 왼쪽 오른쪽 같은 경우
      } else if (tmpL === tmpR) {
        //왼손잡이라면 왼쪽 이용
        if (hand === "left") {
          left = list[x];
          answer += "L";
          //오른손잡이일 경우
        } else {
          right = list[x];
          answer += "R";
        }
      }
    }
  }
  return answer;
}

코드 설명 : 객체 배열을 이용하여 키패드 정보를 입력해줍니다. 그 후 numbers배열을 반복하면서 해당 키패드의 위치정보를 받아와서 1,2,3,3-1 조건을 해결해주면됩니다.

첫번째 풀이와 달라진 것은 키패드 정보를 이차원 배열로 했냐 객체 배열을 이용했냐 차이입니다.

나머지 알고리즘은 동일합니다.

하지만 시간복잡도는 O(n^3)에서 O(n)으로 줄어 확실히 효율적인 코드가 되었습니다.

 

* 문제 유형에 따른 알고리즘 선택이 중요하다는 것을 알 수 있었던 문제입니다. 또한 항상 정답만 맞출 것이 아니라 다른 사람의 코드를 보면서 리팩토링하는 습관이 중요합니다.

728x90
Comments