본문 바로가기

CS/알고리즘&문제풀이

[프로그래머스] 베스트 앨범

https://school.programmers.co.kr/learn/courses/30/lessons/42579

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 해시 테이블을 사용하는 문제다. 자바스크립트에는 이에 대응되는 Map이 있으므로, 이를 이용하여 문제를 풀었다. 

function solution(genres, plays) {
    const map = new Map();

    genres.forEach((gen, idx) => {
        const target = map.get(gen);
        if (!target) {
        	// 해당 장르에 대한 초기 세팅.
            map.set(gen, { total: plays[idx], arr: [[plays[idx], idx], [0, 0]] });
        } else {
            const arr = target.arr;
            
            // 2개밖에 안되서 그냥 if문으로 비교함.
            // 저장하는 곡 개수가 많았다면 for문 사용했을 듯?
            if (plays[idx] > arr[0][0]) { // 재생횟수 비교
                arr[1] = arr[0]; 
                arr[0] = [plays[idx], idx];
            } else if (plays[idx] > arr[1][0]) {
                arr[1] = [plays[idx], idx];
            }
            target.total += plays[idx]; // 재생 횟수 추가
        }
    });

    const list = [...map.values()]; // iter 객체 배열로
    list.sort((a, b) => {
        return b.total - a.total; // total 기준 내림차순 정렬
    });
    const result = [];
    for (let i = 0; i < list.length; i++) {
        list[i].arr.forEach(it => {
            if (it[0] > 0) { // 재생 횟수 존재하는 경우(실제 값인 경우)
                result.push(it[1]);
            }
        })
    }
    return result;
}

 genres와 plays는 동일한 길이를 가진 배열이다. 파이썬을 사용했다면 둘을 zip 함수로 묶었겠지만, 자바스크립트에는 대응되는 함수가 없으나, 배열 대상으로 iteration을 수행하는 forEach, map, filter 등을 이용하면 대응되는 인덱스도 알 수 있다. 이러한 성질을 이용하기 위해 forEach 함수를 사용했다.

 map에는 객체를 저장했는데, 해당 객체가 가진 데이터는 다음과 같다.

  • total: 대응되는 장르에 대한 전체 재생 횟수를 의미
  • arr: 장르 내 재생 횟수가 높은 곡에 대한 [재생 횟수, 인덱스] 정보

 target을 통해 현재 대응되는 장르가 맵에 존재하지 않는 경우, 위 정보를 기본으로 넣었다. 반대로 존재하는 경우 arr 내 저장된 곡들의 재생 횟수를 비교하여 맞는 위치로 저장했다. 현재는 if문을 이용하여 하드코딩으로 위치를 옮겼으나, 만약 곡의 개수가 3개 이상이었다면 for문을 순회했을 것이다. if문을 아래 코드로 바꿔도 동일하게 동작한다. 동작만 보면 삽입 정렬과 매우 유사한 것 같다.

for (let i = 0; i < arr.length; i++) {
    if (plays[idx] > arr[i][0]) {
        for (let j = arr.length - 1; j > i; j--) {
            arr[j] = arr[j - 1];
        }
        arr[i] = [plays[idx], idx];
        break;
    }
}

 이후 장르의 이름에는 관심이 없으므로 map.values()을 통해 객체에 대한 iter 객체를 받아 배열로 변환하고, total 값을 기준으로 내림차순 정렬했다. 정렬된 배열에서 [재생횟수, 인덱스] 튜플이 담긴 함수로부터 인덱스 값을 가져와서 반환할 배열에 넣었다. 이때 재생 횟수가 0인 경우는 처음에 초기화하고 값이 변한 적 없는 경우이므로 제외했다.

오늘도 한문제 풀었다...