⚡문제정보


처음으로 제 힘으로 푼 3레벨 문제입니다만..
정답률이 50%나 되는 3레벨 중엔 쉬운 문제네용..
물론 저는 쉽게 못 풀었습니다.
문제를 풀면서 주의할 점은 다음과 같습니다.
🙄주의사항
1. 각 장르별로 가장 많이 플레이 된 곡을 2개씩 뽑아와야합니다.
** 이때 장르에 곡이 한개밖에 없는 경우도 존재합니다.
2. 각 장르에 속한 곡의 모든 플레이 수를 합산하여 가장 플레이수가 많은 순서대로 나열해야합니다.
** 단일 곡의 플레이수를 기준으로 정렬해선 안됩니다.
3.고유번호는 배열 인덱스입니다.
4. 합산플레이가 많은 장르 순서대로 곡을 나열해야합니다.
** 각 장르별 가장 플레이수가 많은 곡을 찾기위한 정렬(1)과
합산플레이가 많은 장르 순서대로 나열하기 위한 정렬(2)
즉 정렬이 두번 필요합니다.
🔍접근방법
1. 각 장르의 총 플레이수의 합산을 얻어야 할 것입니다.
2. 정확한 분류를 위해 각 곡들의 인덱스, 장르, 플레이수를 알아야 할 것입니다.
3. 2에서 얻은 분류를 토대로 각 장르의 최다플레이곡 2개를 순서대로 뽑아옵니다.
4. 1에서 얻은 분류를 토대로 각 장르의 총플레이순서로 정렬시켜주고 idx만을 담은 배열로 리턴합니다.
🔍나의 풀이
function solution(genres, plays) {
let map = new Map()
let set = [...new Set(genres)]
let result = []
let playCounter = new Map()
for(i=0 ; i<set.length ; i++) {
map.set(set[i],[])
}
for(i=0; i<genres.length; i++) {
let pusher = map.get(genres[i])
pusher.push(
{
genre : genres[i],
idx : i,
playCnt : plays[i]
}
)
playCounter.set(genres[i], (playCounter.get(genres[i]) || 0) + plays[i] )
}
[...map].forEach(ele => {
ele[1].sort((a,b) => b.playCnt - a.playCnt)
if(ele[1].length > 1) {
result.push([ele[1][0],ele[1][1]])
}
else result.push([ele[1][0]])
})
result.sort((a,b) => playCounter.get(b[0].genre) - playCounter.get(a[0].genre) )
return result
.map(ele => ele.map(answer => answer.idx))
.reduce((acc,cur) => acc.concat(cur))
}
나름... 가독성있게 코드를 작성하려고 노력했는데
다른 사람이 보기에는 어떨지 모르겠네요
function solution(genres, plays) {
let map = new Map()
// 모든 값을 저장할 Map입니다.
let set = [...new Set(genres)]
// 각 장르를 set을 통해 중복없게 만들어줍니다.
let result = []
// 정답을 반환할 배열
let playCounter = new Map()
// 장르별 총 플레이합산을 구하기 위한 Map입니다.
for(i=0 ; i<set.length ; i++) {
map.set(set[i],[])
// map의 밸류값으로 배열을 설정해줌
// 이 작업을 위해 위에서 set을 선언한것
// Map자료구조의 밸류값으로 배열을 두고 조작하기 위해 이 for문을 사용함
}
for(i=0; i<genres.length; i++) {
let pusher = map.get(genres[i])
// 변수를 선언하고 변수에 get한 밸류값을 할당해줌
pusher.push(
{
genre : genres[i],
idx : i,
playCnt : plays[i]
}
)
//get 값에 genre,idx,playCnt를 담은 객체를 push해줍니다.
playCounter.set(genres[i], (playCounter.get(genres[i]) || 0) + plays[i] )
// playCounter에 각 장르별 총플레이수를 합산시켜줍니다.
}
[...map].forEach(ele => {
// map에 forEach를 돌립니다.
// 굳이 전개하지않아도 Map자료구조에 바로 forEach를 할수있긴합니다만...
// 일단 익숙한 형태로 하기위해 배열로 바꿔준 뒤 forEach를 돌렸습니다.
ele[1].sort((a,b) => b.playCnt - a.playCnt)
// b.객체키값을 통해 객체를 특정 키값을 기준으로 정렬시킬수있습니다.
// 이때 ele[0]은 장르값이고 ele[1]은 배열안에 객체들이 담긴 형태로 있습니다.
// 따라서 그 객체들을 playCnt기준으로 정렬해주는 작업입니다.
if(ele[1].length > 1) {
result.push([ele[1][0],ele[1][1]])
}
//장르의 곡이 단 한개일수도 있기때문에 if문으로 예외처리를 해줍니다.
//각 장르마다 제일 많이 플레이된 곡 2개를 순서대로 배열안에 넣은 형태로
//result 배열에 push합니다
else result.push([ele[1][0]])
//곡이 단 한개면 그 곡을 result 배열에 push 합니다.
})
result.sort((a,b) => playCounter.get(b[0].genre) - playCounter.get(a[0].genre) )
// 각 장르의 최다플레이수를 get으로 가져와서 get값을 기준으로 정렬해줍니다.
return result
.map(ele => ele.map(answer => answer.idx))
.reduce((acc,cur) => acc.concat(cur))
// map을 두번 사용해서 각 객체들을 idx만 남은 형태로 만들어준다음
// reduce를 이용해 2차원배열 형태인 값들을 1차원배열로 만들어주고 리턴합니다.
}
이뭔씹인데 콘솔찍으면서 각 과정에서의 흐름을 보면... 이해가 잘 될거에요...
이미 각 과정흐름을 봐야하는 시점에서 가독성 망한건가요? ㅈㅅ..
최근에 다시 풀어봤습니다.
function solution(genres, plays) {
const obj = {};
const maxGenre = new Map();
const answer = [];
genres.reduce((obj, genre, idx) => {
Array.isArray(obj[genre])
? obj[genre].push([idx, plays[idx]])
: (obj[genre] = [[idx, plays[idx]]]);
maxGenre.set(genre, (maxGenre.get(genre) || 0) + plays[idx]);
return obj;
}, obj);
for (key in obj) {
obj[key]?.sort((a, b) => b[1] - a[1]);
}
const sorted = [...maxGenre].sort((a, b) => b[1] - a[1]);
for (let i = 0; i < sorted.length; i++) {
for (let j = 0; j < 2; j++) {
let key = sorted[i][0];
if(obj[key].length < 2 && j > 0) break
answer.push(obj[key][j][0]);
}
}
return answer
}
key값을 두개씩 넣어주는 과정에서 장르에 담긴 곡이 한개밖에 없는 케이스를 고려해줘야합니다.
고부분을 고려해주지않으면 런타임에러가 발생해요
🔍테케로 보는 스피드웨건
["classic", "pop", "classic", "classic", "pop"], [500, 600, 150, 800, 2500]
위 테스트케이스를 기준으로 코드를 보겠읍니다..
for(i=0; i<genres.length; i++) {
let pusher = map.get(genres[i])
pusher.push(
{
genre : genres[i],
idx : i,
playCnt : plays[i]
}
)
playCounter.set(genres[i], (playCounter.get(genres[i]) || 0) + plays[i] )
}
이 코드의 실행이 완료된 시점에서
map과 playCounter의 상태는 다음과 같습니다.
map => Map(2) {
'classic' => [
{ genre: 'classic', idx: 0, playCnt: 500 },
{ genre: 'classic', idx: 2, playCnt: 150 },
{ genre: 'classic', idx: 3, playCnt: 800 }
],
'pop' => [
{ genre: 'pop', idx: 1, playCnt: 600 },
{ genre: 'pop', idx: 4, playCnt: 2500 }
]
}
// map의 상황
playCounter => Map(2) { 'classic' => 1450, 'pop' => 3100 }
// playCounter의 상황
각 장르를 기준으로 객체에 값이 잘 담긴 모습을 확인할 수 있읍니다.
키 : 밸류형태에서
밸류가 [객체,객체,객체] 형태로 담겨있는 구조네용
이제 이걸 forEach합니다.
[...map].forEach(ele => {
ele[1].sort((a,b) => b.playCnt - a.playCnt)
if(ele[1].length > 1) {
result.push([ele[1][0],ele[1][1]])
}
else result.push([ele[1][0]])
console.log(ele)
})
이 forEach는 총 2번 도는데 classic에 먼저 접근하고 pop에 접근한 다음 순회를 마칠것입니다.
ele[1]로 밸류에 접근한다음 각 배열을 playCnt를 기준으로 정렬합니다.
그리고 if문에 맞게 result에 push해주면 이때 상태는 이렇습니다.
// [...map]의 상태
[
'classic',
[
{ genre: 'classic', idx: 3, playCnt: 800 },
{ genre: 'classic', idx: 0, playCnt: 500 },
{ genre: 'classic', idx: 2, playCnt: 150 }
]
]
[
'pop',
[
{ genre: 'pop', idx: 4, playCnt: 2500 },
{ genre: 'pop', idx: 1, playCnt: 600 }
]
]
// result의 상태
[
[
{ genre: 'classic', idx: 3, playCnt: 800 },
{ genre: 'classic', idx: 0, playCnt: 500 }
],
[
{ genre: 'pop', idx: 4, playCnt: 2500 },
{ genre: 'pop', idx: 1, playCnt: 600 }
]
]
각 장르의 최다플레이수를 기준으로 정렬되고
result에 상위 2곡이 순서대로 push된걸 확인할 수 있군용
[ [객체모음 ], [객체모음] ]과 같이 2차원 배열 형태로 result가 구성됩니다.
result.sort((a,b) => playCounter.get(b[0].genre) - playCounter.get(a[0].genre) )
return result
.map(ele => ele.map(answer => answer.idx))
.reduce((acc,cur) => acc.concat(cur))
이제 get값을 기준으로 정렬해주고
map을 두번 사용해서 2차원 배열에 담긴 객체들을 고유번호(idx)로 변환해줍니다.
map을 두번 거친 후 상태는 다음과 같습니다.
[[4,1],[3,0]]
값 자체는 맞는데 2차원 배열 형태로 값이 담겨졌네요
이걸 이제 concat으로 합쳐주면 1차원 배열이 되면서 원하는 값을 얻습니다.
🔍다른 사람의 멋진 풀이
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);
}
genres.forEach((t,i))로 plays의 인덱스까지 접근하면서
단 한줄의 삼항연산자로 각 장르의 총합플레이를 세어서 dic에 저장해주네용
그러고 genres에 map을해서
각 요소를 genre , 재생횟수, 고유번호를 담은 객체로 바꿔주고
sort를 하는데 sort 부분은 잘 이해가 안되네용... 따흑흑
'programmers' 카테고리의 다른 글
[Programmers Level 2] 할인 행사 Javascript (0) | 2023.01.11 |
---|---|
[Programmers Level 2] 괄호 회전하기 Javascript (0) | 2023.01.11 |
[Programmers Level 2] H-index Javascript (0) | 2022.12.31 |
[Programmers Level 1] 문자열 나누기 Javascript (0) | 2022.12.30 |
[Programmers Level 2] 짝지어 제거하기 Javascript (0) | 2022.12.27 |
⚡문제정보


처음으로 제 힘으로 푼 3레벨 문제입니다만..
정답률이 50%나 되는 3레벨 중엔 쉬운 문제네용..
물론 저는 쉽게 못 풀었습니다.
문제를 풀면서 주의할 점은 다음과 같습니다.
🙄주의사항
1. 각 장르별로 가장 많이 플레이 된 곡을 2개씩 뽑아와야합니다.
** 이때 장르에 곡이 한개밖에 없는 경우도 존재합니다.
2. 각 장르에 속한 곡의 모든 플레이 수를 합산하여 가장 플레이수가 많은 순서대로 나열해야합니다.
** 단일 곡의 플레이수를 기준으로 정렬해선 안됩니다.
3.고유번호는 배열 인덱스입니다.
4. 합산플레이가 많은 장르 순서대로 곡을 나열해야합니다.
** 각 장르별 가장 플레이수가 많은 곡을 찾기위한 정렬(1)과
합산플레이가 많은 장르 순서대로 나열하기 위한 정렬(2)
즉 정렬이 두번 필요합니다.
🔍접근방법
1. 각 장르의 총 플레이수의 합산을 얻어야 할 것입니다.
2. 정확한 분류를 위해 각 곡들의 인덱스, 장르, 플레이수를 알아야 할 것입니다.
3. 2에서 얻은 분류를 토대로 각 장르의 최다플레이곡 2개를 순서대로 뽑아옵니다.
4. 1에서 얻은 분류를 토대로 각 장르의 총플레이순서로 정렬시켜주고 idx만을 담은 배열로 리턴합니다.
🔍나의 풀이
function solution(genres, plays) {
let map = new Map()
let set = [...new Set(genres)]
let result = []
let playCounter = new Map()
for(i=0 ; i<set.length ; i++) {
map.set(set[i],[])
}
for(i=0; i<genres.length; i++) {
let pusher = map.get(genres[i])
pusher.push(
{
genre : genres[i],
idx : i,
playCnt : plays[i]
}
)
playCounter.set(genres[i], (playCounter.get(genres[i]) || 0) + plays[i] )
}
[...map].forEach(ele => {
ele[1].sort((a,b) => b.playCnt - a.playCnt)
if(ele[1].length > 1) {
result.push([ele[1][0],ele[1][1]])
}
else result.push([ele[1][0]])
})
result.sort((a,b) => playCounter.get(b[0].genre) - playCounter.get(a[0].genre) )
return result
.map(ele => ele.map(answer => answer.idx))
.reduce((acc,cur) => acc.concat(cur))
}
나름... 가독성있게 코드를 작성하려고 노력했는데
다른 사람이 보기에는 어떨지 모르겠네요
function solution(genres, plays) {
let map = new Map()
// 모든 값을 저장할 Map입니다.
let set = [...new Set(genres)]
// 각 장르를 set을 통해 중복없게 만들어줍니다.
let result = []
// 정답을 반환할 배열
let playCounter = new Map()
// 장르별 총 플레이합산을 구하기 위한 Map입니다.
for(i=0 ; i<set.length ; i++) {
map.set(set[i],[])
// map의 밸류값으로 배열을 설정해줌
// 이 작업을 위해 위에서 set을 선언한것
// Map자료구조의 밸류값으로 배열을 두고 조작하기 위해 이 for문을 사용함
}
for(i=0; i<genres.length; i++) {
let pusher = map.get(genres[i])
// 변수를 선언하고 변수에 get한 밸류값을 할당해줌
pusher.push(
{
genre : genres[i],
idx : i,
playCnt : plays[i]
}
)
//get 값에 genre,idx,playCnt를 담은 객체를 push해줍니다.
playCounter.set(genres[i], (playCounter.get(genres[i]) || 0) + plays[i] )
// playCounter에 각 장르별 총플레이수를 합산시켜줍니다.
}
[...map].forEach(ele => {
// map에 forEach를 돌립니다.
// 굳이 전개하지않아도 Map자료구조에 바로 forEach를 할수있긴합니다만...
// 일단 익숙한 형태로 하기위해 배열로 바꿔준 뒤 forEach를 돌렸습니다.
ele[1].sort((a,b) => b.playCnt - a.playCnt)
// b.객체키값을 통해 객체를 특정 키값을 기준으로 정렬시킬수있습니다.
// 이때 ele[0]은 장르값이고 ele[1]은 배열안에 객체들이 담긴 형태로 있습니다.
// 따라서 그 객체들을 playCnt기준으로 정렬해주는 작업입니다.
if(ele[1].length > 1) {
result.push([ele[1][0],ele[1][1]])
}
//장르의 곡이 단 한개일수도 있기때문에 if문으로 예외처리를 해줍니다.
//각 장르마다 제일 많이 플레이된 곡 2개를 순서대로 배열안에 넣은 형태로
//result 배열에 push합니다
else result.push([ele[1][0]])
//곡이 단 한개면 그 곡을 result 배열에 push 합니다.
})
result.sort((a,b) => playCounter.get(b[0].genre) - playCounter.get(a[0].genre) )
// 각 장르의 최다플레이수를 get으로 가져와서 get값을 기준으로 정렬해줍니다.
return result
.map(ele => ele.map(answer => answer.idx))
.reduce((acc,cur) => acc.concat(cur))
// map을 두번 사용해서 각 객체들을 idx만 남은 형태로 만들어준다음
// reduce를 이용해 2차원배열 형태인 값들을 1차원배열로 만들어주고 리턴합니다.
}
이뭔씹인데 콘솔찍으면서 각 과정에서의 흐름을 보면... 이해가 잘 될거에요...
이미 각 과정흐름을 봐야하는 시점에서 가독성 망한건가요? ㅈㅅ..
최근에 다시 풀어봤습니다.
function solution(genres, plays) {
const obj = {};
const maxGenre = new Map();
const answer = [];
genres.reduce((obj, genre, idx) => {
Array.isArray(obj[genre])
? obj[genre].push([idx, plays[idx]])
: (obj[genre] = [[idx, plays[idx]]]);
maxGenre.set(genre, (maxGenre.get(genre) || 0) + plays[idx]);
return obj;
}, obj);
for (key in obj) {
obj[key]?.sort((a, b) => b[1] - a[1]);
}
const sorted = [...maxGenre].sort((a, b) => b[1] - a[1]);
for (let i = 0; i < sorted.length; i++) {
for (let j = 0; j < 2; j++) {
let key = sorted[i][0];
if(obj[key].length < 2 && j > 0) break
answer.push(obj[key][j][0]);
}
}
return answer
}
key값을 두개씩 넣어주는 과정에서 장르에 담긴 곡이 한개밖에 없는 케이스를 고려해줘야합니다.
고부분을 고려해주지않으면 런타임에러가 발생해요
🔍테케로 보는 스피드웨건
["classic", "pop", "classic", "classic", "pop"], [500, 600, 150, 800, 2500]
위 테스트케이스를 기준으로 코드를 보겠읍니다..
for(i=0; i<genres.length; i++) {
let pusher = map.get(genres[i])
pusher.push(
{
genre : genres[i],
idx : i,
playCnt : plays[i]
}
)
playCounter.set(genres[i], (playCounter.get(genres[i]) || 0) + plays[i] )
}
이 코드의 실행이 완료된 시점에서
map과 playCounter의 상태는 다음과 같습니다.
map => Map(2) {
'classic' => [
{ genre: 'classic', idx: 0, playCnt: 500 },
{ genre: 'classic', idx: 2, playCnt: 150 },
{ genre: 'classic', idx: 3, playCnt: 800 }
],
'pop' => [
{ genre: 'pop', idx: 1, playCnt: 600 },
{ genre: 'pop', idx: 4, playCnt: 2500 }
]
}
// map의 상황
playCounter => Map(2) { 'classic' => 1450, 'pop' => 3100 }
// playCounter의 상황
각 장르를 기준으로 객체에 값이 잘 담긴 모습을 확인할 수 있읍니다.
키 : 밸류형태에서
밸류가 [객체,객체,객체] 형태로 담겨있는 구조네용
이제 이걸 forEach합니다.
[...map].forEach(ele => {
ele[1].sort((a,b) => b.playCnt - a.playCnt)
if(ele[1].length > 1) {
result.push([ele[1][0],ele[1][1]])
}
else result.push([ele[1][0]])
console.log(ele)
})
이 forEach는 총 2번 도는데 classic에 먼저 접근하고 pop에 접근한 다음 순회를 마칠것입니다.
ele[1]로 밸류에 접근한다음 각 배열을 playCnt를 기준으로 정렬합니다.
그리고 if문에 맞게 result에 push해주면 이때 상태는 이렇습니다.
// [...map]의 상태
[
'classic',
[
{ genre: 'classic', idx: 3, playCnt: 800 },
{ genre: 'classic', idx: 0, playCnt: 500 },
{ genre: 'classic', idx: 2, playCnt: 150 }
]
]
[
'pop',
[
{ genre: 'pop', idx: 4, playCnt: 2500 },
{ genre: 'pop', idx: 1, playCnt: 600 }
]
]
// result의 상태
[
[
{ genre: 'classic', idx: 3, playCnt: 800 },
{ genre: 'classic', idx: 0, playCnt: 500 }
],
[
{ genre: 'pop', idx: 4, playCnt: 2500 },
{ genre: 'pop', idx: 1, playCnt: 600 }
]
]
각 장르의 최다플레이수를 기준으로 정렬되고
result에 상위 2곡이 순서대로 push된걸 확인할 수 있군용
[ [객체모음 ], [객체모음] ]과 같이 2차원 배열 형태로 result가 구성됩니다.
result.sort((a,b) => playCounter.get(b[0].genre) - playCounter.get(a[0].genre) )
return result
.map(ele => ele.map(answer => answer.idx))
.reduce((acc,cur) => acc.concat(cur))
이제 get값을 기준으로 정렬해주고
map을 두번 사용해서 2차원 배열에 담긴 객체들을 고유번호(idx)로 변환해줍니다.
map을 두번 거친 후 상태는 다음과 같습니다.
[[4,1],[3,0]]
값 자체는 맞는데 2차원 배열 형태로 값이 담겨졌네요
이걸 이제 concat으로 합쳐주면 1차원 배열이 되면서 원하는 값을 얻습니다.
🔍다른 사람의 멋진 풀이
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);
}
genres.forEach((t,i))로 plays의 인덱스까지 접근하면서
단 한줄의 삼항연산자로 각 장르의 총합플레이를 세어서 dic에 저장해주네용
그러고 genres에 map을해서
각 요소를 genre , 재생횟수, 고유번호를 담은 객체로 바꿔주고
sort를 하는데 sort 부분은 잘 이해가 안되네용... 따흑흑
'programmers' 카테고리의 다른 글
[Programmers Level 2] 할인 행사 Javascript (0) | 2023.01.11 |
---|---|
[Programmers Level 2] 괄호 회전하기 Javascript (0) | 2023.01.11 |
[Programmers Level 2] H-index Javascript (0) | 2022.12.31 |
[Programmers Level 1] 문자열 나누기 Javascript (0) | 2022.12.30 |
[Programmers Level 2] 짝지어 제거하기 Javascript (0) | 2022.12.27 |