출처: 프로그래머스 코딩테스트 조이스틱 (Greedy) 2번째 문제
(https://programmers.co.kr/learn/courses/30/lessons/42862)
조이스틱으로 알파벳 이름을 완성하세요. 맨 처음엔 A로만 이루어져 있습니다.
ex) 완성해야 하는 이름이 세 글자면 AAA, 네 글자면 AAAA
조이스틱을 각 방향으로 움직이면 아래와 같습니다.
▲ - 다음 알파벳
▼ - 이전 알파벳 (A에서 아래쪽으로 이동하면 Z로)
◀ - 커서를 왼쪽으로 이동 (첫 번째 위치에서 왼쪽으로 이동하면 마지막 문자에 커서)
▶ - 커서를 오른쪽으로 이동
예를 들어 아래의 방법으로 "JAZ"를 만들 수 있습니다.
따라서 11번 이동시켜 "JAZ"를 만들 수 있고, 이때가 최소 이동입니다.
만들고자 하는 이름 name이 매개변수로 주어질 때, 이름에 대해 조이스틱 조작 횟수의 최솟값을 return 하도록 solution 함수를 만드세요.
function solution(name) {
let answer = 0
const INITIAL_CHAR = "A",
LEFT = -1,
RIGHT = 1
const visited = new Array(name.length).fill(false)
const move = (idx, direction, visited) => {
if (isVisitedAll(visited)) return
visited[idx] = true
answer += getCharChangeCnt(INITIAL_CHAR, name[idx])
if (direction === RIGHT) {
if (name[idx + 1] === "A") {
const aCnt = getACnt(name, idx + 1)
if (idx + aCnt === name.length) return
if (isGoToBack(name.length, idx, aCnt)) {
pass(visited, idx, aCnt)
answer += idx + 1
move(name.length - 1, LEFT, visited)
return
}
}
}
answer++
move(idx + direction, direction, visited)
}
move(0, RIGHT, visited)
return answer - 1
}
const isVisitedAll = (visited) => visited.every((el) => el === true)
const getCharChangeCnt = (a, b) => {
const cnt = b.charCodeAt(0) - a.charCodeAt(0)
if (cnt > 12) {
return 26 - cnt
}
return cnt
}
const getACnt = (str, idx) => {
let cnt = 0
while (str[idx++] === "A") {
cnt++
}
return cnt
}
const pass = (visited, idx, aCnt) => {
for (let i = idx; i <= idx + aCnt; i++) {
visited[i] = true
}
}
const isGoToBack = (size, idx, aCnt) => {
const processCnt = idx * 2
const remainCnt = size - 1 - idx - aCnt
return size > processCnt + remainCnt
}
이 문제를 풀면서 이것이 그리디한 문제인지 조금 혼란이 왔다. 아직까지도 이게 그리디한 문제인지 잘은 모르겠다.