두 개의 문자열을 인수로 받아, 문자의 등장 순서나 대소문자와 관계없이 두 문자열이 서로 같은 문자들로 구성되어 있는지 판별하는 isEqual() 함수를 작성해야 한다고 가정해 봅시다.
예를 들어 다음과 같습니다.
const first = 'Aavsg';
const second = 'VSAAg';
isEqual(first, second); // true
즉, 두 문자열에 포함된 문자의 종류와 개수만 같다면 순서나 대소문자가 달라도 true를 반환해야 합니다. 이를 구현하는 대표적인 방법 두 가지를 살펴보겠습니다.
방법 1: 배열로 변환해 정렬 후 비교하기
가장 직관적인 접근 방식입니다. 문자열을 배열로 분리한 뒤 Array.prototype.sort() 메서드로 알파벳순 정렬하고, 다시 하나의 문자열로 결합한 다음 두 결과가 완전히 일치하는지 비교합니다.
예제 코드
const first = 'Aavsg';
const second = 'VSAAg';
// 문자열을 자체적으로 정렬할 수 있도록 String.prototype에 sort 메서드 추가
const stringSort = function () {
return this.split('').sort().join('');
};
String.prototype.sort = stringSort;
const isEqual = (first, second) =>
first.toLowerCase().sort() === second.toLowerCase().sort();
console.log(isEqual(first, second)); // true
먼저 toLowerCase()로 두 문자열을 모두 소문자로 통일한 뒤, 확장된 sort 메서드가 내부적으로 split → sort → join 과정을 수행해 정렬된 문자열을 만들어 줍니다. 마지막으로 두 정렬 결과가 같은지 === 연산자로 비교합니다.
참고로 실무에서는 표준 객체(String.prototype)를 직접 수정하는 방식은 권장되지 않으므로, 아래처럼 별도의 헬퍼 함수로 분리해 사용하는 것이 더 안전하고 깔끔합니다.
const normalize = str => str.toLowerCase().split('').sort().join('');
const isEqual = (first, second) => normalize(first) === normalize(second);
방법 2: Map(객체)로 문자 빈도수 세기
두 번째 방법은 정렬 없이 두 문자열을 동시에 한 글자씩 순회하면서 각 문자의 빈도수를 객체(Map)에 기록하는 방식입니다. 규칙은 다음과 같습니다.
- 첫 번째 문자열에서 해당 문자가 나타나면 값에 +1
- 두 번째 문자열에서 해당 문자가 나타나면 값에 -1
모든 순회가 끝난 후 객체의 모든 값이 0이라면 두 문자열의 문자 구성이 동일한 것이고, 하나라도 0이 아니라면 서로 다르다고 판단합니다.
예제 코드
const first = 'Aavsg';
const second = 'VSAAg';
const isEqual = (first, second) => {
// 길이가 다르면 바로 false 반환
if (first.length !== second.length) {
return false;
}
first = first.toLowerCase();
second = second.toLowerCase();
const map = {};
for (let i = 0; i < first.length; i++) {
// 첫 번째 문자열의 문자는 +1
map[first[i]] = (map[first[i]] || 0) + 1;
// 두 번째 문자열의 문자는 -1
map[second[i]] = (map[second[i]] || 0) - 1;
}
// 모든 값이 0이면 두 문자열은 동일
return Object.values(map).every(val => val === 0);
};
console.log(isEqual(first, second)); // true
함수 초반에 길이를 먼저 비교해 다르면 즉시 false를 반환하므로, 불필요한 순회 연산을 줄일 수 있다는 장점도 있습니다.
두 방법의 성능 비교
정렬 기반 방법(방법 1)의 시간 복잡도는 O(n log n)인 반면, 빈도수 계산 방법(방법 2)은 O(n)으로 문자열이 길어질수록 더 유리합니다. 따라서 짧은 문자열에는 어느 쪽이든 큰 차이가 없지만, 성능이 중요한 환경에서는 Map을 활용한 방법 2를 선택하는 것이 좋습니다.
실행 결과
두 방법 모두 콘솔에는 다음과 같은 결과가 출력됩니다.
true