해당 문제는 꽤나 까다로워서 애를 먹긴 했지만, 함수를 따로 만들어서 문제를 풀었는데요. 일단 문제 풀이를 위한 절차를 설명해보면 다음과 같습니다.
그래서 해당 문제를 커스텀 함수 및 플래그 루프를 이용하여 풀어보았는데요. 알고리즘 설명은 다음 그림을 참조 부탁드립니다!
- 최소 문자 타이핑 횟수를 구하는 함수
(자료 출처 : 미리캔버스로 제작했습니다.)
이때 경우의 수를 생각해야 하는데요. 그건 바로 함수에서 반복문을 돌면서 targets의 특정 문자열의 문자를 keymap의 문자열들에서 찾을 수 없는 경우, 즉 indexOf 메서드를 사용했을 때 -1을 반환 받았을 때의 경우입니다.
그래서 함수에서 keymap만큼 for문을 도는 동안 문자열 마다 indexOf메서드로 letter의 위치를 찾을 때 -1을 반환 받는 경우, 즉 해당 문자열에 찾고자 하는 문자가 없을 때는 다음 for문으로 이어가도록 처리를 해야합니다. 이 말인 즉 반환 받은 값이 -1이 아닐 때 Math.min으로 해당 문자열의 인덱스 + 1값과 minPress의 값을 비교하여 작은 값을 minPress에 할당하는 코드가 실행되도록 해야한다는 것이죠. 바로 아래의 코드처럼요.
// 키맵 길이만큼 반복
for(let i = 0; i < keymap.length; i++){
// 문자열 마다 문자의 최소길이를 구함
let index = keymap[i].indexOf(letter);
// 만약 최소 길이가 -1가 아닌 경우, 즉 찾은 경우라면 아래의 코드를 실행해 최소값을 구함
if(index !== -1) {
minPress = Math.min(minPress, index + 1); // 최소 값을 찾음
}
}
두번째는 문자열을 다 돌아도 해당 문자열이 없는 경우, 즉 minPress가 초기의 값인 Infinity일때입니다. 아시다시피 최소값을 구하는 기본 공식은 처음 비교값으로 Infinity(가장 큰 값)을 할당한 변수와 다른 변수의 값을 비교해 작은 값을 Infinity가 담긴 변수에 할당하는 방식인데요. 모르시는 분들을 위해 아래의 코드를 잠깐 소개해 드릴테니 한 번 코드 과정을 생각해 보시면 좋을 듯 합니다!
let arr = [1,2,3,4,5,6,7,8,9,10]; // JS에서 가장 큰 값을 최소값을 담을 변수에 초기화 let minNum = Infinity; // JS에서 가장 작은 값을 최대값을 담을 변수에 초기화 let maxNum = -Infinity; for(let i = 0 ; i < arr.length ; i++){ if(arr[i] < minNum) minNum = arr[i]; if(arr[i] > maxNum) maxNum = arr[i]; } console.log(`최소값은 ${minNum} 입니다.`); console.log(`최대값은 ${maxNum} 입니다.`);
이제 본문으로 돌아와서, 함수에서 minPress의 값이 초기에 할당했던 Infinity 값이라는건 keymap의 그 어느 문자열도 해당 문자를 처리할 수 없는 상태라는 뜻이므로 -1를 반환하도록 해야하는거죠.
return minPress === Infinity ? -1 : minPress;
이것만 해주시면 그 아래 코드는 그리 큰 어려움이 아니므로 해당 문제를 JS 버전으로 푼 코드를 소개해 드리면서 주석으로 설명해 드리겠습니다!
- 자바스크립트 버전
function solution(keymap, targets) { let result = []; function countButtonPressingNumber(letter) { let minPress = Infinity; // 최소 키 누름 횟수를 무한대로 초기화 for(let i = 0; i < keymap.length; i++){ let index = keymap[i].indexOf(letter); if(index !== -1) { minPress = Math.min(minPress, index + 1); // 최소 값을 찾음 } } return minPress === Infinity ? -1 : minPress; } // for문을 targets만큼 돌리면서 각 버튼을 누른 횟수를 합산하 count와 플래그 루프 사용을 위한 flag 변수를 false로 할당 for(let i = 0; i < targets.length; i++){ let count = 0; let flag = false; // for문을 다시 targets의 각 문자열의 길이만큼 돌리면서 각 문자들을 위에서 선언한 함수에 넘겨주고 최소값을 반환받음 for(let j = 0; j < targets[i].length; j++){ let ctn = countButtonPressingNumber(targets[i][j]); // 만약 반환받은 값이 -1, 즉 최소값을 찾지 못했다면 flag를 true로 바꾸고 for문 종료 if(ctn === -1){ flag = true; break; // -1이 아닐경우 count에 차곡차곡 담아줌 } else { count += ctn; } } // 해당 문자열에 대해 flag가 발생 된 경우, 즉 문자열 중 최소값을 찾지 못한 문자가 존재하면 문자열을 온전히 완성할 수 없으므로 result 배열에 -1를 할당 if(flag) result.push(-1); // 그게 아니라면 result 배열에 누적된 count(문자열 완성을 위해 누른 최소 버튼수)를 할당 else result.push(count); } // targets의 for문이 다 끝났다면 최종적으로 result를 반환 return result; }
그리고 자바 버전으로 구현한 코드는 다음과 같습니다.
- 자바 버전
import java.util.ArrayList; import java.util.List; public class Solution { public static List<Integer> solution(String[] keymap, String[] targets) { List<Integer> resultList = new ArrayList<>(); for (String target : targets) { int count = 0; boolean flag = false; for (int j = 0; j < target.length(); j++) { int ctn = countButtonPressingNumber(keymap, target.charAt(j)); if (ctn == -1) { flag = true; break; } else count += ctn; } if (flag) resultList.add(-1); else resultList.add(count); } return resultList; } public static int countButtonPressingNumber(String[] keymap, char letter) { int minPresses = Integer.MAX_VALUE; // 최소 키 누름 횟수를 매우 큰 값으로 초기화 for (String key : keymap) { int index = key.indexOf(letter); if (index != -1) { minPresses = Math.min(minPresses, index + 1); // 최소 값을 찾음 } } return minPresses == Integer.MAX_VALUE ? -1 : minPresses; } }
JS의 경우에서 양의 무한대와 음의 무한대 값으로 Infinity와 -Infinity, 즉 쉽게 생성 가능한데요. 자바의 경우 Integer 래퍼 클래스의 상수 필드인 MAX_VALUE와 MIN_VALUE를 사용해야 합니다.
JS의 경우 인덱스의 접근이나 반환등의 방법이 쉬운 반면, 자바의 경우 타입을 지정하고 클래스 메서드로 변환해서 접근하거나 반환해야 하므로 은근 신경쓸 부분이 제법 있었습니다.