이번 글에서는 최소 하나 이상의 모음을 포함하는 문자열을 입력받아, 문자열의 각 문자에 대해 가장 가까운 모음까지의 거리를 숫자로 매핑한 배열을 반환하는 JavaScript 함수를 작성해 보겠습니다.
문제 이해하기
예를 들어 다음과 같은 문자열이 있다고 가정해 보겠습니다.
const str = 'vatghvf';
이 경우 첫 번째 문자 'v'는 모음 'a'(인덱스 1)와 거리가 1이고, 두 번째 문자 'a'는 자체가 모음이므로 거리가 0입니다. 나머지 문자들은 왼쪽의 모음 'a'에서 점점 멀어지므로 거리가 1씩 증가합니다.
출력 결과
따라서 기대되는 출력은 다음과 같습니다.
const output = [1, 0, 1, 2, 3, 4, 5];
구현 방법
이 문제를 해결하는 접근 방식은 다음과 같습니다.
- 먼저 문자열을 소문자로 변환하여 대소문자 구분 없이 모음을 판별할 수 있도록 합니다.
- 문자열을 순회하면서 모음('a', 'e', 'i', 'o', 'u')의 인덱스를 별도의 배열에 저장합니다.
- 각 문자 위치에 대해 저장된 모음 인덱스들과의 거리를 계산하고, 그중 최솟값을 선택합니다.
코드 예제
위 로직을 코드로 구현하면 다음과 같습니다.
const str = 'vatghvf';
// 주어진 요소(el)와 배열 내 값들 사이의 최소 거리를 계산하는 헬퍼 함수
const nearest = (arr = [], el) =>
arr.reduce((acc, val) => Math.min(acc, Math.abs(val - el)), Infinity);
// 각 문자에서 가장 가까운 모음까지의 거리를 계산하는 함수
const vowelNearestDistance = (str = '') => {
const s = str.toLowerCase();
const vowelIndex = [];
// 모음의 인덱스를 수집
for (let i = 0; i < s.length; i++) {
if (s[i] === 'a' || s[i] === 'e' || s[i] === 'i' || s[i] === 'o' || s[i] === 'u') {
vowelIndex.push(i);
}
}
// 각 문자 위치에서 가장 가까운 모음까지의 거리를 매핑
return s.split('').map((el, ind) => nearest(vowelIndex, ind));
};
console.log(vowelNearestDistance(str));실행 결과
콘솔에 출력되는 결과는 다음과 같습니다.
[ 1, 0, 1, 2, 3, 4, 5 ]
코드 설명
nearest 함수는 reduce 메서드를 활용해 배열의 모든 요소와 목표 인덱스 사이의 절댓값 차이 중 최솟값을 찾습니다. 초기값으로 Infinity를 사용하여 어떤 거리보다도 큰 값에서 비교를 시작합니다.
vowelNearestDistance 함수는 먼저 toLowerCase()로 대소문자를 통일한 뒤, 반복문을 통해 모음의 위치를 수집합니다. 마지막으로 split('')으로 문자열을 문자 배열로 변환하고 map을 사용해 각 위치별 최단 거리를 계산한 새로운 배열을 반환합니다.
이 알고리즘의 시간 복잡도는 O(n × m)입니다. 여기서 n은 문자열의 길이, m은 모음의 개수입니다. 문자열이 매우 길다면 양방향 스캔(two-pass) 방식을 활용해 O(n)으로 최적화할 수도 있습니다.