Development/알고리즘

[프로그래머스 | Javascript] Lv.1 키패드 누르기

레오나르도 다빈츠 2024. 12. 2. 23:59

 

처음에 읽자마자 "이건 트리다!"라고 당당하게 생각한 뒤 코드를 짰다. 그런데.. 최소경로를 구하기위해 DFS로 접근하려고보니 트리라는 자료구조가 이 문제와 맞지 않다는 판단이 들었다. 더 정리를 해보자면 단순히 부모-자식 관계를 갖고있고 노드를 순차적으로 방문할 수 있다는 사실 하나로 트리로 접근했지만... 상위 부모가 하나인 트리가 이상해보였다. 그리고 키패드 구조상 트리처럼 단방향이 아닌 서로 연결될 수 있는 양방향 연결이 가능하고 싸이클이 존재하는 자료구조가 필요하다는 사실을 깨닫는다.

 

예전에 공부했던 자료구조 책을 펼쳐보고 '이건 그래프로 풀어야 하는거구나' 이마를 탁 치고 그래프로 접근했다. (조금 성장한 듯..) 그래프에 대해 공부하며 맨해튼 거리에 대해서도 알게됐다. 알고리즘 넘 재밌어..🥺

 

const PRIORITY_LEVEL = {
  left: [1, 4, 7],
  right: [3, 6, 9],
  center: [2, 5, 8, 0],
}

const graph = new Map()
function addEdges(node, neighbors) {
  graph.set(node, new Set(neighbors))
}

function DFS(start, target, visited = new Set(), distance = 0) {
  if (start === target) return distance

  visited.add(start)
  let minDistance = Infinity

  // 인접한 노드를 DFS로 탐색
  for (const neighbor of graph.get(start)) {
    if (!visited.has(neighbor)) {
      const dist = DFS(neighbor, target, visited, distance + 1)
      if (dist < minDistance) minDistance = dist // 최소 거리 갱신
    }
  }

  visited.delete(start)
  return minDistance
}

const solution = (numbers, hand) => {
  // Map(10) {
  //   1 => Set(3) { 2, 4, 5 },
  //   2 => Set(4) { 1, 3, 5, 4 },
  //   3 => Set(3) { 2, 6, 5 },
  //   4 => Set(4) { 1, 5, 7, 2 },
  //   5 => Set(9) { 2, 3, 4, 6, 8, 1, 7, 9, 0 },
  //   6 => Set(4) { 3, 5, 9, 2 },
  //   7 => Set(4) { 4, 8, 5, 0 },
  //   8 => Set(6) { 4, 5, 6, 7, 9, 0 },
  //   9 => Set(4) { 6, 8, 5, 0 },
  //   0 => Set(3) { 7, 8, 9 }
  // }
  addEdges(1, [2, 4])
  addEdges(2, [1, 3, 5])
  addEdges(3, [2, 6])
  addEdges(4, [1, 5, 7])
  addEdges(5, [2, 4, 6, 8])
  addEdges(6, [3, 5, 9])
  addEdges(7, [4, 8, '*'])
  addEdges(8, [5, 7, 9, 0])
  addEdges(9, [6, 8, '#'])
  addEdges(0, [8, '*', '#'])
  addEdges('*', [7, 0])
  addEdges('#', [9, 0])

  const lastPushedKey = {
    right: '*',
    left: '#',
  }

  const pushKey = (direction, pushedKey) => {
    if (direction === 'right') {
      result.push('R')
      lastPushedKey.right = pushedKey
    } else {
      result.push('L')
      lastPushedKey.left = pushedKey
    }
  }

  const result = []
  numbers.forEach((pushedKey) => {
    if (PRIORITY_LEVEL['right'].includes(pushedKey)) {
      pushKey('right', pushedKey)
    } else if (PRIORITY_LEVEL['left'].includes(pushedKey)) {
      pushKey('left', pushedKey)
    } else if (PRIORITY_LEVEL['center'].includes(pushedKey)) {
      const leftHandDistance = DFS(lastPushedKey.left, pushedKey)
      const rightHandDistance = DFS(lastPushedKey.right, pushedKey)

      if (leftHandDistance > rightHandDistance) {
        pushKey('right', pushedKey)
      } else if (leftHandDistance < rightHandDistance) {
        pushKey('left', pushedKey)
      } else if (leftHandDistance === rightHandDistance) {
        hand === 'right' ? pushKey('right', pushedKey) : pushKey('left', pushedKey)
      }
    }
  })

  return result.join('')
}

console.log(solution([1, 3, 4, 5, 8, 2, 1, 4, 5, 9, 5], 'right'))