2025. 3. 6. 20:24ㆍ프로그래머스/LV.3
문제링크: 베스트앨범
문제설명
스트리밍 사이트에서 장르 별로 가장 많이 재생된 노래를 두 개씩 모아 베스트 앨범을 출시하려 합니다. 노래는 고유 번호로 구분하며, 노래를 수록하는 기준은 다음과 같습니다.
속한 노래가 많이 재생된 장르를 먼저 수록합니다.
장르 내에서 많이 재생된 노래를 먼저 수록합니다.
장르 내에서 재생 횟수가 같은 노래 중에서는 고유 번호가 낮은 노래를 먼저 수록합니다.
노래의 장르를 나타내는 문자열 배열 genres와 노래별 재생 횟수를 나타내는 정수 배열 plays가 주어질 때, 베스트 앨범에 들어갈 노래의 고유 번호를 순서대로 return 하도록 solution 함수를 완성하세요.
제한조건
- genres[i]는 고유번호가 i인 노래의 장르입니다.
- plays[i]는 고유번호가 i인 노래가 재생된 횟수입니다.
- genres와 plays의 길이는 같으며, 이는 1 이상 10,000 이하입니다.
- 장르 종류는 100개 미만입니다.
- 장르에 속한 곡이 하나라면, 하나의 곡만 선택합니다.
- 모든 장르는 재생된 횟수가 다릅니다.
문제풀이
딕셔너리를 2개 쓰려나 하나를 이중 딕셔너리를 쓰면 되지 않나? 해서 한개로만 했는데.... 이중 딕셔너리를 사용해도 결국 2개의 딕셔너리가 필요했다.
장르의 각 총 재생횟수와
장르에 속해있는 각 노래의 재생횟수
이렇게 두 개의 딕셔너리를 만들었다.
그다음에 딕셔너리를 벨류값 기준으로 정렬하여 풀었다.
근데 약간 돌아돌아 간 느낌이 있다. 더 간결하게 할 수 있을 것 같은데...
gpt 한테 물어봄..근데 튜플을 쓰는 거 빼고 딱히 변한건 없는듯?
1. genres_cnt의 구조 변경
genres_cnt에서 {i: plays[i]} 구조로 저장하는 대신, genres_cnt를 {genre: [(index, play), (index, play), ...]} 형태로 만드는 것이 더 직관적이고 효율적입니다. 그 후, sorted()를 통해 정렬할 때 리스트를 한번에 처리할 수 있기 때문에 반복문을 줄일 수 있습니다.
2. sorted()의 활용
genres_total을 기준으로 먼저 장르를 정렬한 후, 각 장르의 곡들을 두 번째로 정렬하는 방식이 됩니다. 이를 통해 이중으로 정렬을 최소화할 수 있습니다.
3. 두 번째 정렬을 한 번에 처리
정렬을 한 번만 하는 것이 효율적입니다. genres_cnt의 값을 리스트로 저장하고, 그 리스트를 한 번에 정렬하는 방식으로 진행합니다.
수정된 코드
def solution(genres, plays):
answer = []
genres_cnt = {} # 각 장르별 노래 정보
genres_total = {} # 각 장르별 총 재생 횟수
# 각 장르별 곡 재생 횟수 합산 및 노래 정보 저장
for i in range(len(genres)):
if genres[i] in genres_cnt:
genres_cnt[genres[i]].append((i, plays[i]))
genres_total[genres[i]] += plays[i]
else:
genres_cnt[genres[i]] = [(i, plays[i])]
genres_total[genres[i]] = plays[i]
# 장르별 총 재생 횟수로 내림차순 정렬
sorted_genres = sorted(genres_total.items(), key=lambda x: x[1], reverse=True)
# 각 장르에 대해 곡들을 정렬하고, 최대 2개까지 결과에 추가
for genre, _ in sorted_genres:
# 장르에 속한 곡들을 재생 횟수 내림차순으로 정렬
sorted_songs = sorted(genres_cnt[genre], key=lambda x: x[1], reverse=True)[:2]
answer.extend([song[0] for song in sorted_songs]) # 곡의 index만 결과에 추가
return answer
수정된 코드 설명
- genres_cnt 구조 변경:
- 이제 genres_cnt는 {genre: [(index, plays), (index, plays), ...]} 형태로 저장됩니다.
- 각 장르에 속한 곡의 (index, plays)를 튜플로 저장하여, 정렬할 때 손쉽게 처리할 수 있습니다.
- genres_total 처리:
- genres_total은 {genre: total_play} 형태로, 각 장르의 총 재생 횟수를 계산하여 저장합니다.
- 정렬:
- sorted_genres = sorted(genres_total.items(), key=lambda x: x[1], reverse=True)는 각 장르를 총 재생 횟수에 따라 내림차순으로 정렬합니다.
- 각 장르별로 genres_cnt[genre] 리스트를 재생 횟수 기준으로 내림차순으로 정렬하고, 상위 2개 곡만 추출합니다.
- 결과에 인덱스 추가:
- 각 장르에서 최대 2개의 곡을 뽑을 때, 인덱스를 answer 리스트에 추가합니다.
효율성 향상
- 정렬 최적화:
- sorted()를 두 번 호출하는 대신, genres_cnt의 곡들을 한번에 정렬하여 필요한 곡만 추출합니다.
- genres_total을 먼저 정렬한 후, 각 장르의 곡들을 개별적으로 정렬합니다.
- 리스트 활용:
- genres_cnt에서 곡 정보를 리스트로 처리하여, sorted()를 사용할 때 직접 비교할 수 있게 하여 코드의 직관성을 높였습니다.
- extend() 사용:
- answer += sorted_song 대신 answer.extend()를 사용하여 sorted_song 리스트를 한 번에 추가하도록 변경했습니다.
결과
이 코드는 가독성을 높이고, 불필요한 반복을 줄이며, 전체적인 성능을 향상시킬 수 있습니다.
나의코드
코def solution(genres, plays):
answer = []
genres_cnt={}
genres_total={}
# 이중해시?
# 딕셔너리 2번 쓰는것보다 딕셔너리를 이중으로 쓰는게 좋을듯?
for i in range(len(genres)):
if genres[i] in genres_cnt:
# 딕셔너리 안의 딕셔너리에 추가하는 법.
genres_cnt[genres[i]][i]=plays[i]
genres_total[genres[i]]+=plays[i]
else:
genres_cnt[genres[i]]={i:plays[i]}
genres_total[genres[i]]=plays[i]
# print(genres_cnt)
sorted_genres=sorted(genres_total.keys(),key=lambda k: genres_total[k],reverse=True)
# print(sorted_genres)
for key in sorted_genres:
# # 재생횟수 비교
# max1,max2=0,0
# # 노래 번호
# num1,num2=0,0
# for k,v in genres[key].items():
# 그냥 sort해서 앞에거 2개 가지고 오면 되지 않나?
sorted_song=sorted(genres_cnt[key].keys(), key=lambda k: genres_cnt[key][k],reverse=True)[:2]
answer+=sorted_song
return answer
참고하기
def solution(genres, plays):
answer = []
d = {e:[] for e in set(genres)}
for e in zip(genres, plays, range(len(plays))):
d[e[0]].append([e[1] , e[2]])
genreSort =sorted(list(d.keys()), key= lambda x: sum( map(lambda y: y[0],d[x])), reverse = True)
for g in genreSort:
temp = [e[1] for e in sorted(d[g],key= lambda x: (x[0], -x[1]), reverse = True)]
answer += temp[:min(len(temp),2)]
return answer
zip에 range(len(plays))를 사용하여 인덱스까지 같이 표현해줌
def solution(genres, plays):
answer = []
total_play = {}
music_list = {}
# 1. 장르별 총 재생 횟수 계산
for i, g in enumerate(genres):
total_play[g] = total_play.get(g, 0) + plays[i]
# 2. 장르별 재생 횟수 기준으로 정렬
# ['pop', 'classic']
sorted_genres = sorted(total_play, key=lambda x: -total_play[x])
# 3. 장르별 노래 리스트 생성
# {'classic': [(500, 0), (150, 2), (800, 3)], 'pop': [(600, 1), (2500, 4)]}
for i, (g, p) in enumerate(zip(genres, plays)):
music_list[g] = music_list.get(g, []) + [(p, i)] # (재생 횟수, 고유번호)
# 4. 정렬된 장르별 곡 정렬 (재생 횟수 내림차순, 고유번호 오름차순)
#{'classic': [(800, 3), (500, 0), (150, 2)], 'pop': [(2500, 4), (600, 1)]}
temp = {}
for genre, songs in music_list.items():
songs.sort(key=lambda x: (-x[0], x[1])) # 재생 횟수 내림차순, 고유번호 오름차순
temp[genre] = songs # 정렬된 리스트 저장
# 5. 베스트 앨범 생성 (각 장르에서 최대 2곡)
for s in sorted_genres:
answer.append(temp[s][0][1]) # 가장 많이 재생된 곡 추가
if len(temp[s]) > 1:
answer.append(temp[s][1][1]) # 두 번째로 많이 재생된 곡 추가
return answer
def solution(genres, plays):
answer = []
dic1 = {}
dic2 = {}
for i, (g, p) in enumerate(zip(genres, plays)):
if g not in dic1:
dic1[g] = [(i, p)]
else:
dic1[g].append((i, p))
if g not in dic2:
dic2[g] = p
else:
dic2[g] += p
for (k, v) in sorted(dic2.items(), key=lambda x:x[1], reverse=True):
for (i, p) in sorted(dic1[k], key=lambda x:x[1], reverse=True)[:2]:
answer.append(i)
return answer
해당 장르의 곡과 플레이 횟수를 나는 이중 딕셔너리로 저장했는데 튜플을 활용하여 더 간단하게 저장할 수 있다.
'프로그래머스 > LV.3' 카테고리의 다른 글
[프로그래머스][LV.3] 네트워크 | python3 (0) | 2025.03.21 |
---|---|
[프로그래머스][LV.3] 섬 연결하기 | python3 (0) | 2025.03.20 |
[프로그래머스][LV.3] 아이템 줍기 | python3 (0) | 2025.03.19 |
[프로그래머스][LV.3] 이중우선순위큐 | python3 (0) | 2025.03.14 |
[프로그래머스][LV.3] 디스크 컨트롤러 | python3 (0) | 2025.03.13 |