문제 이해하기
두 개의 숫자 배열을 입력받아, 두 배열 중 한쪽에만 존재하고 양쪽에 공통으로 포함되지 않은 요소들을 반환하는 JavaScript 함수를 작성해야 합니다. 수학적으로 말하면 두 배열의 대칭 차집합(symmetric difference)을 구하는 것과 같습니다.
예를 들어 다음과 같은 두 배열이 있다고 가정해 보겠습니다.
const arr1 = [2, 4, 2, 4, 6, 4, 3]; const arr2 = [4, 2, 5, 12, 4, 1, 3, 34];
기대 출력
두 배열 모두에 공통으로 포함된 값은 2, 4, 3입니다. 따라서 결과는 이 공통 요소들을 제외한 나머지 값들이어야 합니다.
const output = [6, 5, 12, 1, 34];
구현 방법
가장 직관적인 접근 방식은 첫 번째 배열의 각 요소가 두 번째 배열에 존재하는지 확인하고, 존재하지 않으면 결과 배열에 추가하는 것입니다. 그다음 반대로 두 번째 배열의 각 요소가 첫 번째 배열에 존재하지 않는 경우에도 결과 배열에 추가합니다.
배열의 indexOf() 메서드는 찾는 요소가 배열에 없을 때 -1을 반환하므로, 이를 활용하면 손쉽게 구현할 수 있습니다.
const arr1 = [2, 4, 2, 4, 6, 4, 3];
const arr2 = [4, 2, 5, 12, 4, 1, 3, 34];
const deviations = (first, second) => {
const res = [];
// 첫 번째 배열에서 두 번째 배열에 없는 요소 찾기
for(let i = 0; i < first.length; i++){
if(second.indexOf(first[i]) === -1){
res.push(first[i]);
}
}
// 두 번째 배열에서 첫 번째 배열에 없는 요소 찾기
for(let j = 0; j < second.length; j++){
if(first.indexOf(second[j]) === -1){
res.push(second[j]);
}
}
return res;
};
console.log(deviations(arr1, arr2));
실행 결과
콘솔에 출력되는 결과는 다음과 같습니다.
[6, 5, 12, 1, 34]
코드 설명
deviations함수는 두 개의 배열을 매개변수로 받습니다.- 첫 번째 반복문에서는
first배열의 요소가second배열에 없으면(indexOf결과가-1) 결과 배열res에 추가합니다. - 두 번째 반복문에서는 그 반대 경우, 즉
second배열의 요소가first배열에 없을 때 추가합니다. - 최종적으로 양쪽에 공통되지 않은 모든 요소를 담은 배열을 반환합니다.
성능 개선 팁: Set 활용하기
indexOf()는 배열을 처음부터 끝까지 선형 탐색하므로 시간 복잡도가 O(n)입니다. 따라서 위 코드의 전체 시간 복잡도는 O(n×m)이 됩니다. 배열의 크기가 클 경우 Set 객체를 사용하면 O(1) 조회로 성능을 크게 개선할 수 있으며, 부수적으로 중복 제거 효과도 얻을 수 있습니다.
const deviationsWithSet = (first, second) => {
const set1 = new Set(first);
const set2 = new Set(second);
const res = [];
for(const num of set1){
if(!set2.has(num)) res.push(num);
}
for(const num of set2){
if(!set1.has(num)) res.push(num);
}
return res;
};
두 방식 모두 동일한 결과를 반환하지만, 데이터 크기가 커질수록 Set 기반 구현이 훨씬 효율적입니다. 상황에 맞게 적절한 방법을 선택해 사용하시기 바랍니다.