문제

프로그래머스-조이스틱

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
조이스틱으로 알파벳 이름을 완성하세요. 맨 처음엔 A로만 이루어져 있습니다.
ex) 완성해야 하는 이름이 세 글자면 AAA, 네 글자면 AAAA

조이스틱을 각 방향으로 움직이면 아래와 같습니다.

▲ - 다음 알파벳
▼ - 이전 알파벳 (A에서 아래쪽으로 이동하면 Z로)
◀ - 커서를 왼쪽으로 이동 (첫 번째 위치에서 왼쪽으로 이동하면 마지막 문자에 커서)
▶ - 커서를 오른쪽으로 이동 (마지막 위치에서 오른쪽으로 이동하면 첫 번째 문자에 커서)
예를 들어 아래의 방법으로 "JAZ"를 만들 수 있습니다.

- 첫 번째 위치에서 조이스틱을 위로 9번 조작하여 J를 완성합니다.
- 조이스틱을 왼쪽으로 1번 조작하여 커서를 마지막 문자 위치로 이동시킵니다.
- 마지막 위치에서 조이스틱을 아래로 1번 조작하여 Z를 완성합니다.
  따라서 11번 이동시켜 "JAZ"를 만들 수 있고, 이때가 최소 이동입니다.
  만들고자 하는 이름 name이 매개변수로 주어질 때, 이름에 대해 조이스틱 조작 횟수의 최솟값을 return 하도록 solution 함수를 만드세요.

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function solution(name) {
  const n = name.length;
  let sum = 0;
  let minMove = n - 1;

  for (let i = 0; i < n; i++) {
    // 위, 아래 버튼을 눌러 타겟으로 바꾸는 연산
    let up = name[i].charCodeAt() - "A".charCodeAt();
    let down = "Z".charCodeAt() - name[i].charCodeAt() + 1;
    sum = sum + Math.min(up, down);

    // 왼쪽, 오른쪽 방향으로 이동해 최대한 A를 건너뛸수있는 거리 계산
    let next = i + 1;
    while (next < n && name[next] === "A") {
      next++;
    }
    minMove = Math.min(minMove, 2 * i + (n - next), (n - next) * 2 + i);
  }

  return sum + minMove;
}

풀이

A문자열을 임의의 코드로 변경하는 부분은 어렵지 않았다. 커서를 위로올렸을때와 내렸을때의 값만 비교하면 됬으니까.

문제는 조이스틱를 왼쪽과 오른쪽으로 움직였을때의 최단경로를 찾는 부분

“AAAAAAAAB” 라는 데이터가 있다면 왼쪽이동시 8, 오른쪽은 한번만 움직이면된다.

핵심은 최대한 의미없는 거리 (생략가능한 AAAAA..에 접근하지 않고 순회하는 것) 이였다.

즉 , 각 인덱스를 순회하면서 A가 아닌 다음문자까지 도달하는데 최단거리를 반복문으로 계산하는것!!

이때 고려해야하는 경우의 수는 총 3가지

A A B A A A A A Z 라는 문자열이 있다고 가정하자. 반복문을 돌면서 B에서 Z로 가는 경우의수를 계산해보자

(반복분을 돌면서 0번째 인덱스부터 계산을 하겠지만 결국 가장 많은 A가 붙어있는(생략 가능한 거리가 가장 큰) i=2일때(B~Z) 계산된 minValue값이 최소값이 될것이다.)

  1. 그냥 무조건 직진

    • A-A-B-A-A-A-A-A-Z
    • 8 (n)
  2. 왼쪽으로 이동했다가, B에서 뒤로방향을 틀어서 목적지로

    • A-A-B-A-A-Z
    • 5 (i+i+n-next)
  3. 처음부터 오른쪽으로 목적지로 갔다가, 다시 왼쪽으로 B로

    • A-Z-A-A-B
    • 4 (n-next + n-next + i)

즉 이 3가지 케이스에 대한 최소값을 연산해가며 최대한의 이동거리를 계산하는게 핵심이였다.


안이;; 이게 2단계??

댓글남기기