Algorithm - level1 키패드 누르기

ryan·2022년 5월 16일
0

프로그래머스 : 키패드 누르기

내 풀이(20/100)

function solution(numbers, hand) {
  var answer = '';
  const pad = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
    ['*', 0, '#'],
  ];

  // 양손 위치의 초기값 설정
  let [leftRi, leftCi] = [3, 0];
  let [rightRi, rightCi] = [3, 2];

  numbers.forEach((e) => {
    // 1,4,7인 경우 L을 추가하고 손 위치를 변경
    if(e === 1 || e=== 4 || e===7){
        answer += 'L';
        for (let i = 0; i < pad.length; i++) {
          if (pad[i][0] === e) {
            leftRi = i;
            leftCi = 0;
            break;
          }
        }
    }
   // 3,6,9인 경우 R을 추가하고 손 위치를 변경
      else if(e === 3 || e=== 6 || e===9){
        answer += 'R';
        for (let i = 0; i < pad.length; i++) {
          if (pad[i][0] === e) {
            rightRi = i;
            rightCi = 0;
            break;
          }
        }
      }
    
    // 2,5,8,0인 경우
      else if (e === 2 || e=== 5 || e===8 || e===0){
    // row 위치 계산을 위해 0인 경우 11로 변경
        if (e === 0) {
          let num = 11;
        } else {
          let num = e;
        }
    // num의 위치 구하기   
        let [nextRi, nextCi] = [Math.floor(num - 1) / 3, 1];
    // 왼손과 num 사이의 거리 구하기
        let LeftDistance = Math.abs(leftRi - nextRi) + Math.abs(leftCi - nextCi);
    // 왼손과 num 사이의 거리 구하기
        let RigthDistance = Math.abs(rightRi - nextRi) + Math.abs(rightCi - nextCi);
        if (LeftDistance < RigthDistance || (LeftDistance === RigthDistance && hand === 'left')) {
          answer += 'L';
          leftRi = nextRi;
          leftCi = nextCi;
        } else {
        }
        answer += 'R';
        rightRi = nextRi;
        rightCi = nextCi;
    }
  });
  return answer;
}

다른 사람 풀이 뜯어보기

function solution(numbers, hand) {
  // 키패드를 4행 3열의 이차원 배열이라고 생각

  // leftRow, leftCol: 왼손의 현재 위치
  let [leftRow, leftCol] = [3, 0];
  // rightRow, rightCol: 오른손의 현재 위치
  let [rightRow, rightCol] = [3, 2];
  // 각 번호를 누른 엄지손가락이 어느 손인지 저장할 문자열
  let result = "";

  // 눌러야할 각 번호가
  numbers.forEach((e) => {
    // 1/4/7이면 왼손으로 눌러야하므로
    if (e === 1 || e === 4 || e === 7) {
      // 왼손의 위치 업데이트
      [leftRow, leftCol] = [Math.floor((e - 1) / 3), 0];
      // result 문자열에 "L" 이어붙여줌
      result += "L";
    }

    // 3/6/9이면 오른손으로 눌러야하므로
    else if (e === 3 || e === 6 || e === 9) {
      // 오른손의 위치 업데이트
      [rightRow, rightCol] = [Math.floor((e - 1) / 3), 2];
      // result 문자열에 "R" 이어붙여줌
      result += "R";
    }

    // 2/5/8/0이면
    else {
      // 번호 위치 계산의 편의를 위해 눌러야 할 번호가 0일 경우 11로 바꿔줌
      if (e === 0) e = 11;

      // leftRow, leftCol: 다음에 눌러야 할 번호의 위치
      let [nextRow, nextCol] = [Math.floor((e - 1) / 3), 1];
      // leftDistance: 현재 왼손의 위치와 다음에 눌러야 할 번호의 위치 사이의 거리
      let leftDistance =
        Math.abs(leftRow - nextRow) + Math.abs(leftCol - nextCol);
      // rightDistance: 현재 오른손의 위치와 다음에 눌러야 할 번호의 위치 사이의 거리
      let rightDistance =
        Math.abs(rightRow - nextRow) + Math.abs(rightCol - nextCol);

      // 왼손이 다음에 눌러야 할 번호의 위치와 더 가깝거나, 두 손의 거리가 같으면서 왼손잡이라면 왼손으로 눌러야하므로
      if (
        leftDistance < rightDistance ||
        (leftDistance == rightDistance && hand === "left")
      ) {
        // 왼손의 위치 업데이트
        [leftRow, leftCol] = [nextRow, nextCol];
        // result 문자열에 "L" 이어붙여줌
        result += "L";
      }

      // 오른손이 다음에 눌러야 할 번호의 위치와 더 가깝거나, 두 손의 거리가 같으면서 오른손잡이라며 오른손으로 눌러야하므로
      else {
        // 오른손의 위치 업데이트
        [rightRow, rightCol] = [nextRow, nextCol];
        // reuslt 문자열에 "R" 이어붙여줌
        result += "R";
      }
    }
  });

  // result 문자열 반환
  return result;
}

2차원 배열의 형태로 접근하는 방식은 동일했지만, 왼손/오른손 위치를 재설정하는 식부터 비효율적으로 작성한 것 같고, 2580이 나왔을 때 거리를 구하는 로직에서 어딘가 실수가 발생했는지, 문제의 접근 방식과 해결 방식은 유사했으나 다른 사람의 풀이와 다른 결과가 발생했다. 내일 아침 다시 풀어볼 예정

다시 풀어봄(100/100)

function solution(numbers, hand) {
  let answer = '';
  let [leftRi, leftCi] = [3, 0];
  let [rightRi, rightCi] = [3, 2];

  numbers.forEach((e) => {
    if (e === 0) e === 11;
    if (e === 1 || e === 4 || e === 7) {
      answer += 'L';
      [leftRi, leftCi] = [Math.floor((e - 1) / 3), 0];
      return;
    }
    if (e === 3 || e === 6 || e === 9) {
      answer += 'R';
      [rightRi, rightCi] = [Math.floor((e - 1) / 3), 0];
      return;
    }
    if (e === 2 || e === 5 || e === 8 || e === 0) {
      if (e === 0) e = 11;
      let [nextRi, nextCi] = [Math.floor((e - 1) / 3), 1];
      let leftDistance = Math.abs(nextRi - leftRi) + Math.abs(nextCi - leftCi);
      let rightDistance = Math.abs(nextRi - rightRi) + Math.abs(nextCi - rightCi);
      if (leftDistance < rightDistance || (leftDistance === rightDistance && hand === 'left')) {
        answer += 'L';
        [leftRi, leftCi] = [nextRi, nextCi];
        return;
      } else if (leftDistance > rightDistance || (leftDistance === rightDistance && hand === 'right')) {
        answer += 'R';
        [rightRi, rightCi] = [nextRi, nextCi];
        return;
      }
    }
  });
  return answer;
}

결국은 실수의 문제였다. 비교연산자와 대입연산자를 헷갈려서 썼거나, 키패드를 누르고 손의 위치를 초기화시키지 않았거나 하는 실수들이 쌓여 점수를 깎았다. 이차원 배열을 활용한 문제 해결이지만 이차원 배열을 직접적으로 이용하진 않았다. 이런 식으로 머리에 이차원 배열을 상상하면서 구조화시키고 식을 전개해나갈 수 있다는 것을 알게 됐다.

profile
프론트엔드 개발자

0개의 댓글