문제 상황
다음과 같은 숫자 배열이 있다고 가정해 보겠습니다.
const arr = [1,2,3,4,1,7,8,9,1];
배열에서 가장 작은 요소의 인덱스를 찾고 싶다면 Math.min과 indexOf를 조합하여 간단히 해결할 수 있습니다.
const min = Math.min.apply(Math, arr);
const ind = arr.indexOf(min);
이 코드는 ind에 0을 할당하며, 실제로 올바른 결과입니다.
기존 방식의 한계
그러나 위 배열처럼 최솟값이 여러 개 존재하는 경우(여기서는 1이 세 번 등장)에는 첫 번째 인덱스만 반환하는 것으로는 부족합니다. 우리가 원하는 것은 최솟값 요소의 모든 인덱스를 담은 배열을 얻는 것입니다.
즉, 위 배열에 대한 기대 출력은 다음과 같습니다.
const ind = [0, 4, 8]
해결 방법
숫자 배열을 인자로 받아 최솟값 요소의 모든 인덱스를 배열로 반환하는 JavaScript 함수를 작성해 보겠습니다. 핵심 로직은 두 단계로 나눌 수 있습니다.
- 최솟값 도출:
reduce메서드와 초기값Infinity를 활용해 배열 전체를 순회하며 최솟값을 구합니다. - 인덱스 수집: 반복문으로 각 요소를 검사하여 최솟값과 일치하는 요소의 인덱스만 결과 배열에 추가합니다.
예제 코드
const arr = [1,2,3,4,1,7,8,9,1];
const minArray = arr => {
const min = arr.reduce((acc, val) => Math.min(acc, val), Infinity);
const res = [];
for(let i = 0; i < arr.length; i++){
if(arr[i] !== min){
continue;
};
res.push(i);
};
return res;
};
console.log(minArray(arr));
실행 결과
콘솔에는 다음과 같이 출력됩니다.
[ 0, 4, 8 ]
코드 동작 원리
reduce는 초기값 Infinity부터 시작해 배열의 모든 요소를 비교하며 최종적으로 최솟값(여기서는 1)을 반환합니다. 이후 for 반복문이 배열을 순회하면서 현재 요소가 최솟값과 일치하지 않으면 continue로 건너뛰고, 일치하면 해당 인덱스를 res 배열에 저장합니다. 최종적으로 최솟값이 위치한 모든 인덱스 [0, 4, 8]이 반환됩니다.
이 방식은 배열을 두 번 순회하므로 시간 복잡도는 O(n)이며, 중복된 최솟값이 몇 개든 관계없이 정확한 결과를 보장합니다.