이번 글에서는 양수와 음수가 섞여 있는 숫자 배열을 입력받는 JavaScript 함수를 작성해 보겠습니다.
이 함수의 목표는 배열 안에서 서로 부호만 다른 짝(양수와 그에 대응하는 음수)이 모두 존재하는 값만 골라내어 새로운 배열로 반환하는 것입니다.
예를 들어, 입력 배열이 다음과 같다고 가정해 봅시다.
const arr = [1, 5, -3, -5, 3, 2];
여기서 5와 -5, 3과 -3은 서로 짝을 이루지만, 1과 2에는 대응하는 음수가 없습니다. 따라서 기대되는 출력 결과는 다음과 같습니다.
const output = [5, 3];
해결 접근 방식
이 문제는 해시 객체(카운터)를 활용하면 효율적으로 풀 수 있습니다. 배열을 한 번만 순회하면서 각 요소에 대해 다음을 확인합니다.
- 현재 요소의 부호를 반전한 값(-el)이 이미 카운터에 기록되어 있다면, 두 수는 짝을 이루는 것이므로 절댓값을 결과 배열에 추가합니다.
- 짝이 아직 없다면, 현재 요소를 카운터에 기록해 두어 이후 등장할 짝과 매칭될 수 있도록 준비합니다.
이 방식은 시간 복잡도 O(n)으로 배열을 한 번만 탐색하기 때문에 매우 효율적입니다.
예제 코드
실제 구현 코드는 다음과 같습니다.
const arr = [1, 5, -3, -5, 3, 2];
const findNumbers = (arr = []) => {
const count = Object.create(null);
const result = [];
arr.forEach(el => {
if (count[-el]) {
result.push(Math.abs(el));
count[-el]--;
return;
};
count[el] = (count[el] || 0) + 1;
});
return result;
}
console.log(findNumbers(arr));코드 설명
count: 아직 짝을 찾지 못한 숫자들을 저장하는 객체입니다.Object.create(null)을 사용해 프로토타입 오염 없이 깨끗한 객체를 만듭니다.result: 짝을 이룬 양수 값을 담는 최종 결과 배열입니다.Math.abs(el): 짝이 발견되면 항상 양수 형태로 결과에 저장합니다.count[-el]--: 짝이 하나 소진되었으므로 카운트를 감소시켜 중복 처리를 정확하게 합니다.
실행 결과
위 코드를 실행하면 콘솔에 다음과 같은 출력이 나타납니다.
[5, 3]
결과에서 알 수 있듯이, 5와 3은 각각 -5, -3이라는 음수 짝이 배열 안에 존재하기 때문에 정상적으로 반환되었습니다. 반면 1과 2는 대응하는 음수가 없어 제외되었습니다.