이 글에서는 문자열을 입력받아 그 안의 모음(vowel)만 뒤집어 새 문자열을 반환하는 자바스크립트 함수를 작성하는 방법을 소개합니다. 자음들은 원래 자리에 그대로 두고, 오직 모음들의 순서만 역순으로 바꾸는 것이 핵심입니다.
문제 이해하기
예를 들어, 입력 문자열이 다음과 같다고 가정해 보겠습니다.
const str = 'Hello';
그렇다면 기대되는 출력 결과는 아래와 같습니다.
const output = 'Holle';
'Hello'에는 모음이 e와 o, 두 개 있습니다. 이 두 모음의 위치를 서로 바꾸면 'Holle'이 됩니다. 자음인 H, l, l은 제자리에 그대로 유지됩니다.
접근 방식: 투 포인터(Two Pointer)
가장 효율적인 해결책은 양쪽 끝에서 동시에 출발하는 투 포인터 기법입니다. 동작 과정은 다음과 같습니다.
- 왼쪽 포인터(left)는 문자열의 첫 문자에서, 오른쪽 포인터(right)는 마지막 문자에서 시작합니다.
- 왼쪽 포인터가 모음을 가리킬 때까지 left를 증가시키고, 오른쪽 포인터가 모음을 가리킬 때까지 right를 감소시킵니다.
- 양쪽 모두 모음을 찾았다면 두 문자를 서로 교환(swap)합니다.
- 두 포인터가 만나거나 서로 교차할 때까지 이 과정을 반복합니다.
이 방식은 한 번의 순회(O(n))로 문제를 해결할 수 있어 매우 효율적입니다.
구현 코드
const str = 'Hello';
const reverseVowels = (str = '') => {
const vowels = new Set(['a','e','i','o','u','A','E','I','O','U']);
let left = 0, right = str.length - 1;
let foundLeft = false, foundRight = false;
str = str.split("");
while (left < right) {
if (vowels.has(str[left])) {
foundLeft = true;
}
if (vowels.has(str[right])) {
foundRight = true;
}
if (foundLeft && foundRight) {
[str[left], str[right]] = [str[right], str[left]];
foundLeft = false;
foundRight = false;
}
if (!foundLeft) {
left++;
}
if (!foundRight) {
right--;
}
}
return str.join("");
};
console.log(reverseVowels(str));코드 핵심 포인트
- 모음 집합(Set): 영어 모음의 대소문자를 모두 Set에 담아 두었습니다. Set의 has() 메서드 덕분에 특정 문자가 모음인지 상수 시간(O(1))에 확인할 수 있습니다.
- split()과 join(): 자바스크립트 문자열은 불변(immutable)이기 때문에, 배열로 변환해 문자를 교환한 뒤 마지막에 다시 하나의 문자열로 합칩니다.
- 구조 분해 할당을 활용한 교환: [str[left], str[right]] = [str[right], str[left]] 형태로 임시 변수 없이 두 문자를 깔끔하게 맞바꿉니다.
실행 결과
코드를 실행하면 콘솔에 다음과 같은 결과가 출력됩니다.
Holle