[js] 최빈값 구하기 (lv.0, 정답률 69%)

sookyoung.k·2024년 5월 23일
0
post-thumbnail

최빈값은 주어진 값 중에서 가장 자주 나오는 값을 의미합니다. 정수 배열 array가 매개변수로 주어질 때, 최빈값을 return 하도록 solution 함수를 완성해보세요. 최빈값이 여러 개면 -1을 return 합니다.

제한사항

  • 0 < array의 길이 < 100
  • 0 ≤ array의 원소 < 100

나의 풀이

function solution(array) {
  	// Map() -> key, value 값 저장 
    let counting = new Map();
    for (let i = 0; i < array.length; i++) {
        if (!counting.has(array[i])) {
            counting.set(array[i], 1);
        } else if (counting.has(array[i])) {
            counting.set(array[i], counting.get(array[i]) + 1);
        }
    }

    let maxCount = 0;	// 최대 빈도수 기록 
    let modes = [];		// 최빈값 저장 배열 

    counting.forEach((count, number) => {
        if (count > maxCount) {
            maxCount = count;	// 최대 빈도수 갱신 
            modes = [number];	// 최빈값 배열 초기화
        } else if (count === maxCount) {
            modes.push(number);	// 현재 빈도수가 최대 빈도수와 같다면 최빈값 배열에 추가
        }
    });

  	// 최빈값이 여러개면 -1, 하나라면 그 값을 반환
    if (modes.length > 1) {
        return -1;
    } else return modes[0];
}
  • counting이라는 Map 객체를 생성하여 배열의 각 요소의 등장 횟수를 저장한다

  • 주어진 배열 array를 순회하면서 각 요소가 counting에 존재하는지 확인한다.

    • 존재하지 않으면 해당 요소를 키로, 1을 값으로 설정한다.
    • 이미 존재한다면 해당 요소의 값을 가져와서 1을 더해 다시 설정한다.
  • maxCount는 지금까지 발견된 요소의 최대 등장횟수이다. modes 배열에는 최빈값을 저장한다.

  • counting을 순회하면서 각 요소의 등장 횟수(count)와 요소(number)를 확인한다. 현재 요소의 등장 횟수가 maxCount보다 크다면 갱신, modes 배열을 현재 요소만 포함하도록 초기화한다. 현재 요소의 등장 횟수가 maxCount와 같다면 현재 요소를 modes 배열에 추가한다.

  • 최종적으로 modes 배열의 길이를 확인하여 1보다 크다면 -1을 반환하고 그렇지 않다면 modes[0]을 반환한다.

Map()

Map 객체는 키-값 쌍과 키의 원래 삽입 순서를 기억한다. 키에 대한 다양한 자료형을 사용할 수 있다.

  • clear(): Map 객체의 모든 요소 제거
    ex.map1.clear();
  • delete(): Map 객체에서 특정 요소 제거
    ex. map1.delete('bar');
  • entries(): 새 반복자 객체를 반환
  • forEach(): 삽입 순서에 따라 Map 객체의 각 키/값 쌍마다 한 번씩 제공된 함수를 실행
  • get(): Map 객체에서 특정 요소 반환
  • set(): Map 객체에서 주어진 키와 값을 추가하거나 업데이트
  • has(): 주어진 키에 해당하는 요소가 존재 여부를 가리키는 불리언 값을 반환
  • keys(): 배열에서 각 인덱스의 키를 포함하는 새로운 맵 반복자 객체를 반환
  • values(): 배열의 각 아이템의 값을 순회하는 새로운 맵 반복자 객체를 반환

forEach()

forEach() 메서드는 각 배열 요소에 대해 제공된 함수를 한 번씩 실행한다.

forEach(callbackFn)
forEach(callbackFn, thisArg)

매개변수

  • callbackFn - 배열의 각 요소에 대해 실행할 함수입니다. 반환값은 사용되지 않습니다. 함수는 다음 인수를 사용하여 호출됩니다.

    	- `element` -배열에서 처리 중인 현재 요소.
    	- `index` -배열에서 처리 중인 현재 요소의 인덱스.
    	- `array` - forEach()를 호출한 배열.
  • thisArg Optional - callbackFn을 실행할 때 this 값으로 사용할 값입니다. 순회 메서드를 참조하세요.

반환 값
없음 (undefined).

for 루프를 forEach()로 바꾸기

const items = ["item1", "item2", "item3"];
const copyItems = [];

// 전
for (let i = 0; i < items.length; i++) {
  copyItems.push(items[i]);
}

// 후
items.forEach((item) => {
  copyItems.push(item);
});

다른 풀이 1

function solution(array) {
    let m = new Map();
    for (let n of array) m.set(n, (m.get(n) || 0)+1);
    m = [...m].sort((a,b)=>b[1]-a[1]);
    return m.length === 1 || m[0][1] > m[1][1] ? m[0][0] : -1;
}
  • Map 객체 m을 생성

  • 배열 array를 순회하면서 각 요소 n에 대해 해당 요소의 현재 등장 횟수를 가져온다. 만약 해당 요소가 Map에 존재하지 않으면 undefined를 반환하기 때문에 0을 사용하여 0으로 대체한 다음 1을 더하여 새로운 등장 횟수를 m.set(n, (m.get(n) || 0) + 1)로 Map에 저장한다.

  • m을 배열로 변환한다. Map 객체는 기본적으로 키-밸류 쌍의 배열로 변환된다.

  • 변환된 배열을 sort() 함수를 통해 내림차순으로 정렬한다. b[1] - a[1]은 등장 횟수가 큰 순서대로 정렬한다.

  • 정렬된 배열 m의 길이가 1인 경우, 또는 등장 횟수가 가장 많은 첫 번째 요소의 등장 횟수(m[0][1])가 두 번째 요소의 등장 횟수(m[1][1])보다 큰 경우 최빈값은 유일하므로 m[0][0]를 반환, 그렇지 않으면 최빈값이 여러개 존재하므로 -1을 반환한다.

다른 풀이 2

const solution = (array) => {
    const counter = array.reduce((acc, cur) => ({
        ...acc,
        [cur]: (acc[cur] || 0) + 1
    }), {})

    const items = Object.keys(counter).map((key) => [
        Number(key), counter[key]
    ]).sort((a, b) => b[1] - a[1])

    if (items[0][1] === items?.[1]?.[1]) {
        return -1
    }

    return items[0][0];
}
  • reduce()를 사용하여 배열의 각 요소 cur에 대해 등장 횟수를 계산한다.

  • acc는 누적 객체를 의미하고, 초기값은 빈 객체 {}이다.

  • 새로운 객체를 반환할 때, 현재 요소 cur의 등장 횟수를 증가시킨다. 만약 cur가 객체에 존재하지 않으면 0으로 초기화하고 그렇지 않으면 기존 값에 1을 더한다.

  • Object.keys(counter)를 사용하여 counter의 키를 배열로 가져온다.

  • map()을 사용하여 각 키를 [key, value]쌍의 배열로 변환한다.

  • 변환된 배열을 등장 횟수(value)를 기준으로 내림차순 정렬한다.

  • 정렬된 배열 items에서 가장 높은 등장 횟수를 가진 첫 번째 요소(items[0][1])와 두 번째 요소(items?.[1]?.[1])의 등장 횟수를 비교한다.

  • 두 값이 같으면 최빈값이 여러개 존재하므로 -1을 반환, 그렇지 않으면 최빈값은 유일하므로 첫 번째 요소의 키(items[0][0]을 반환)


이 문제는 푸는데 시간이 꽤 오래걸렸고 다른 사람의 풀이도 이해하는데 시간이 꽤 걸렸던 것으로 기억한다. Map을 사용해서 푼 첫 번째 문제였고, 언젠가 다시 돌아보며 기억하면 좋을 것 같아 기록으로 남김! 미루고 미루다가 이제서야 올린다.

profile
영차영차 😎

0개의 댓글