조이스틱으로 알파벳 이름을 완성하세요. 맨 처음엔 A로만 이루어져 있습니다.
ex) 완성해야 하는 이름이 세 글자면 AAA, 네 글자면 AAAA
조이스틱을 각 방향으로 움직이면 아래와 같습니다.
▲ - 다음 알파벳
▼ - 이전 알파벳 (A에서 아래쪽으로 이동하면 Z로)
◀ - 커서를 왼쪽으로 이동 (첫 번째 위치에서 왼쪽으로 이동하면 마지막 문자에 커서)
▶ - 커서를 오른쪽으로 이동 (마지막 위치에서 오른쪽으로 이동하면 첫 번째 문자에 커서)
예를 들어 아래의 방법으로 "JAZ"를 만들 수 있습니다.
- 첫 번째 위치에서 조이스틱을 위로 9번 조작하여 J를 완성합니다.
- 조이스틱을 왼쪽으로 1번 조작하여 커서를 마지막 문자 위치로 이동시킵니다.
- 마지막 위치에서 조이스틱을 아래로 1번 조작하여 Z를 완성합니다.
따라서 11번 이동시켜 "JAZ"를 만들 수 있고, 이때가 최소 이동입니다.
만들고자 하는 이름 name이 매개변수로 주어질 때, 이름에 대해 조이스틱 조작 횟수의 최솟값을 return 하도록 solution 함수를 만드세요.
name : "JEROEN"
56
name은 알파벳 대문자로만 이루어져 있습니다.
name의 길이는 1 이상 20 이하입니다.
최소 경우를 다음과 같이 찾을 수 있다. 문자열을 바꿀 수 있는 최소 횟수 + 오른쪽 또는 왼쪽으로 cursor를 이동하는 최소 횟수
문자열을 바꿀 수 있는 최소 횟수는 모든 문자가 "A"로 되어 있으므로 해당 문자에서 A까지의 차이를 체크하면 된다. (아스키코드를 활용하면 간단하다.) 하지만, 조이스틱으로 이전 문자열을 할 수 있으므로 A에서 Z로 한 번에 이동할 수 있으니 역방향도 고려해야 한다. 구현하기 쉽게 Z에서 해당 문자까지의 차이를 찾고 A에서 Z로 이동한 횟수 1을 더해준다. 둘 중 더 작은 값이 A에서 원하는 문자열을 만들 수 있는 최소 횟수이다. name에 모든 문자에 대해 최소 횟수의 총합을 answer에 더해준다.
cursor를 이동하는 경우는 오른쪽과 왼쪽이 있지만, 항상 한 방향으로만 이동하지 않아도 된다. 가끔은 돌아가는 게 더 최소 횟수가 될 수 있다. 즉, 오른쪽으로 쭉 이동할 경우 cursor는 n-1번 이동할 수 있고, next는 A가 끝나는 위치를 의미한다. 예를 들어 "BAAAB"인 경우 B에서 다음 문자인 A로 이동해도 문자를 바꿀 필요가 없다. 즉, cursor를 이동하는 경우가 비효율적인 경우는 A가 연속된 경우만 생각하면 된다. 따라서 현재 위치에서 다음 위치를 기준으로 연속된 A가 몇 개 있는지를 체크한다. 왼쪽으로 이동한 뒤에 오른쪽으로 가는 경우는 i*2+n-next가 되고 오른쪽에서 왼쪽으로 돌아오는 경우는 (n-next)*2+i가 된다. 따라서 이 중 최소값을 minMove에 저장해주고 모든 연산이 끝난 뒤에 answer에 더해주면 된다.
function solution(name) {
let answer = 0;
let n = name.length;
let minMove = n - 1;
for (let i = 0; i < n; i++) {
let upDown = Math.min(name.charCodeAt(i) - 'A'.charCodeAt(0),
'Z'.charCodeAt(0) - name.charCodeAt(i) + 1);
answer += upDown;
let next = i + 1;
while (next < n && name[next] === 'A') next++;
minMove = Math.min(minMove, i * 2 + n - next, (n - next) * 2 + i);
}
answer += minMove;
return answer;
}
오른쪽 또는 왼쪽으로 가는 경우밖에 없을거라 생각했는데 오른쪽 갔다가 왼쪽 가는 경우가 최소가 될 수도 있구나... minMove를 이해하기까지 조금 복잡했다. ㅠㅠ