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

김아현·2022년 4월 19일
0

문제 보러가기

🔒 문제

🔐 해결 과정

  1. 장르의 순서 정하기
  2. 장르가 키, 노래 배열이 값인 해시 생성
  3. 장르 순서에 따라 해당 장르의 노래 배열 중 큰 값을 구한 후 plays에서 indexof()로 찾아 결과배열로 push

🔓 풀이 (2h)

1차 시도

function solution(genres, plays) {
  	// 장르 순서 정하기
    let sorted_plays = plays.slice();
    sorted_plays.sort((a,b) => a-b);
    let order = [];
    while(sorted_plays.length){
        let idx = plays.indexOf(sorted_plays.pop());
        if(!order.includes(genres[idx]))
            order.push(genres[idx]);
    }
    
  	// 장르를 키, 노래 배열을 값으로 가지는 객체 생성
    let lists = new Map();
    for(let i=0; i<plays.length; i++){
        if(!lists.has(genres[i])){
            lists.set(genres[i], [plays[i]]);
        } else {
            let pre = lists.get(genres[i]);
            pre.push(plays[i]);
            lists.set(genres[i], pre);
        }
    }
    
  	// 장르 중 최대 재생횟수를 가진 두 노래의 인덱스 찾기
    let result = [];
    order.forEach(x => {
        let musics = lists.get(x).sort((a,b) => b-a);
        let top2 = musics.splice(0,2);
        result.push(...top2.map(x => plays.indexOf(x)));
    })
    return result
}
/*
	채점결과 : 20.0 / 100.0
*/

최다 재생된 두 노래의 인덱스를 찾을 때, 장르를 고려하지 않고 재생횟수가 일치하기만 하면 인덱스를 가져오는 것을 깨달았다. 💦

2차 시도

function solution(genres, plays) {
    let sorted_plays = plays.slice();
    sorted_plays.sort((a,b) => a-b);
    let order = [];
    while(sorted_plays.length){
        let idx = plays.indexOf(sorted_plays.pop());
        if(!order.includes(genres[idx]))
            order.push(genres[idx]);
    }
    
    let lists = new Map();
    for(let i=0; i<plays.length; i++){
        if(!lists.has(genres[i])){
            lists.set(genres[i], [plays[i]]);
        } else {
            let pre = lists.get(genres[i]);
            pre.push(plays[i]);
            lists.set(genres[i], pre);
        }
    }
    
  	// 장르와 재생횟수를 고려하면서, 결과 배열에 포함되어 있는지 확인
    let result = [];
    order.forEach(x => {
        let musics = lists.get(x).sort((a,b) => b-a);
        let top2 = musics.splice(0,2);
        top2.forEach(t => {
            for(let i=0; i<plays.length; i++){
                if(genres[i] === x && plays[i] === t && !result.includes(i)){
                    result.push(i);
                    break;
                }
            }
        })
    })
    return result;
}
/*
	채점결과 : 33.3 / 100.0
*/

ㅎㅎ 이쯤되니 문제를 제대로 이해하지 않았다고 생각이 들어서 다시 차근히 읽어보니 ,, 노래 수록 기준 1번을 적용하지 않았던 것이다 ,, 🥲

3차 시도

function solution(genres, plays) {
  	// 장르의 순서를 누적 횟수 기준으로 변경
    let order = new Map();
    let lists = new Map();
    for(let i=0; i<plays.length; i++){
        if(!lists.has(genres[i])){
            lists.set(genres[i], [plays[i]]);
            order.set(genres[i], plays[i]);
        } else {
            let pre = lists.get(genres[i]);
            pre.push(plays[i]);
            lists.set(genres[i], pre);
            order.set(genres[i], order.get(genres[i]) + plays[i]);
        }
    }
	// 재생횟수를 내림차순으로 정렬한 뒤 장르만 추출
    let tmp = [...order.entries()].sort((a,b) => b[1]-a[1]);
    order = tmp.map(x => x[0]);
    
    let result = [];
    order.forEach(x => {
        let musics = lists.get(x).sort((a,b) => b-a);
        let top2 = musics.splice(0,2);
        top2.forEach(t => {
            for(let i=0; i<plays.length; i++){
                if(genres[i] === x && plays[i] === t && !result.includes(i)){
                    result.push(i);
                    break;
                }
            }
        })
    })
    return result;
}

성공 !!

+ 2022.04.26 추가

function solution(genres, plays) {
    let result = [];
    // 장르별 누적재생횟수
    let map = new Map();
    for(let i=0; i < genres.length; i++){
        map.set(genres[i], (map.get(genres[i]) || 0) + plays[i]);
    }
    // 장르 수록순서
    const sorted_genres = [...map].sort((a,b) => b[1]- a[1]).map(x => x[0]);
    // 2,3번 수록기준에 맞게 두 곡을 선정
    sorted_genres.forEach(genre => {
        let musics = [];
        for(let i=0; i<genres.length; i++){
            if(genres[i] === genre) musics.push([i, plays[i]]);
        }
        let top2 = musics.sort((a,b) => {
            if(a[1] != b[1]) return b[1] - a[1];
            else return a[1] - b[1];
        }).slice(0,2).map(x => x[0]);
        result.push(...top2);
    })
    return result;
}

🔁 feedback

문제에서 나오는 조건을 꼼꼼히 읽고, 의미를 제대로 파악하기

+ 다른사람의 풀이

function solution(genres, plays) {
  	
    var dic = {};
    genres.forEach((t,i)=> {
        dic[t] = dic[t] ?  dic[t] + plays[i] :plays[i];        
    });
	
    var dupDic = {};
    return genres          
          .map((t,i)=> ({genre : t, count:plays[i] , index:i}))
          .sort((a,b)=>{               
               if(a.genre !== b.genre) return dic[b.genre] - dic[a.genre];
               if(a.count !== b.count) return b.count - a.count;
               return a.index - b.index;
           })
           .filter(t=>  {
               if(dupDic[t.genre] >= 2) return false;
               dupDic[t.genre] = dupDic[t.genre] ? dupDic[t.genre]+ 1 : 1;
               return true;
            })
           .map(t=> t.index);  
}
  1. dic에 장르의 순서를 결정하기 위한 재생횟수를 누적한다.
  2. 장르, 재생횟수, 인덱스를 한 객체로 만든다.
  3. 장르의 순서, 한 곡의 재생횟수, 인덱스를 기준으로 다중 sort한다.
  4. dupDic에서 장르의 곡 수가 2 이상이 되면 이후의 노래들은 배제한다.
function solution(genres, plays) {
    const count = {};
    let answer = [];
    const acc = genres.reduce((a, c, i) => {
        debugger;
        count[c] ? count[c].push([i, plays[i]]) : count[c] = [[i, plays[i]]];
        return a.set(c, a.get(c) ? a.get(c) + plays[i] : plays[i]), a;
    }, new Map());

    [...acc].sort((a, b) => b[1] - a[1]).map(v => {
            answer = answer.concat(count[v[0]].sort((c, d)=>d[1]-c[1]).slice(0,2));
    });
    return answer.map(v=>v[0]);
}
  1. count 객체에 노래의 인덱스와 재생횟수 배열로 채운다.
  2. 장르를 키로 하고 재생횟수를 값으로 하는 acc 객체를 생성한다.
  3. acc에서 재생횟수를 기준으로 내림차순 정렬하고, 장르를 하나씩 뽑아 해당하는 노래목록을 내림차순 정렬 후 두 곡을 뽑는다.
profile
Want to be backend developer

0개의 댓글