Today
-
Yesterday
-
Total
-
  • [프로그래머스] 베스트앨범 (Python)
    문제풀이/프로그래머스 2021. 6. 21. 16:04

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

     

    코딩테스트 연습 - 베스트앨범

    스트리밍 사이트에서 장르 별로 가장 많이 재생된 노래를 두 개씩 모아 베스트 앨범을 출시하려 합니다. 노래는 고유 번호로 구분하며, 노래를 수록하는 기준은 다음과 같습니다. 속한 노래가

    programmers.co.kr

     

    def find_best_and_pop(d):
        best = list(d.keys())[0]
        for key in d:
            if d[key] > d[best]:
                best = key
        d.pop(best)
        return best
    
    def last(lst, idx):
        retbool = False
        ret = 0
        if len(lst) >= idx + 2:
            if lst[idx][0] == lst[idx + 1][0]:
                ret = last(lst, idx + 1)[0]
                retbool = True
            else:
                return (idx, retbool)
        else:
            return (idx, retbool)
        return (ret, retbool)
    
    def solution(genres, plays):
        answer = []
        genre = dict()
        total = dict()
        last_idx = 0
    
        for idx in range(len(plays)):
            genre.setdefault(genres[idx], list())
            genre[genres[idx]].append((plays[idx], idx))
            total.setdefault(genres[idx], 0)
            total[genres[idx]] += plays[idx]
        for key in genre:
            genre[key].sort(reverse=True)
        for cnt in range(len(total)):
            best = find_best_and_pop(total)
            if len(genre[best]) == 1:
                answer.append(genre[best][0][1])
            else:
                if last(genre[best], 0)[1] == True:
                    last_idx = last(genre[best], 0)[0]
                    answer.append(genre[best][last_idx][1])
                    answer.append(genre[best][last_idx - 1][1])
                else:
                    answer.append(genre[best][0][1])
                    last_idx = last(genre[best], 1)[0]
                    answer.append(genre[best][last_idx][1])
        return answer

    저보다 훠어얼씬 짧게 푸신 분들도 많지만.. 직관적으로 이해하기 쉽게 풀어봤습니다.

     

    먼저 solution함수가 우리가 만들어야 할 타겟 함수입니다.

    파라미터인 genres와 plays는 각각 리스트로 주어지고, 각각의 인덱스(고유번호)에 따른 벨류는 장르이름과 재생횟수입니다.

    i (고유 번호) i = 0 i = 1 i = 2 ...
    genres[i] (예시) 0번 노래의 장르 (pop) 1번 노래의 장르 (hiphop) 2번 노래의 장르 (pop) ...
    plays[i] (예시) 0번 노래 재생횟수 (20) 1번 노래 재생횟수 (40) 2번 노래 재생횟수 (20) ...

     

    [규칙]

    answer에는 각 장르별로 재생횟수가 가장 많은 곡들의 고유 번호가 들어가야 합니다.

    장르별 총 재생횟수가 가장 많은 장르부터 들어갑니다. (장르별 총 재생횟수는 모두 다릅니다.)

    곡별 재생횟수가 많은 곡부터 최대 두 곡 들어갑니다. (해당 장르에 곡이 하나일 경우 하나만 들어갑니다.)

    곡별 재생횟수가 같은 경우, 고유 번호가 작은 곡부터 들어갑니다.


    [풀이]

    genre와 total은 딕셔너리로 주어집니다.

    genre의 키는 장르 이름으로 들어가며, 벨류는 (재생 횟수, 고유 번호)의 튜플의 리스트로 들어갑니다.

    즉, genre = { 'pop' : [(20, 0), (20, 2)], 'hiphop' : [(40, 1)], ... }

     

    여기에서 쓰인 setdefault(key, value) 메서드는 해당 key에 대한 value가 설정된적이 있으면 스킵, 없으면 해당 value로 초기화됩니다.

     

    total의 키는 장르 이름, 벨류는 장르별 총 재생횟수로 들어갑니다.

    즉, total = { 'pop' : 40, 'hiphop' : 40, ... }

     

    이후 genre 딕셔너리의 각 벨류(리스트)를 역sort 시켜줍니다.

    리스트에 튜플이 담겨 있을 경우, 튜플의 첫번째 원소를 기준으로 1차 정렬, 두번째 원소를 기준으로 2차 정렬이 이루어집니다.

    즉, genre[romance] = [(80, 10), (20, 12), (20, 11), (5, 13)]

     

    이후 total 딕셔너리에서 장르별 총 재생횟수가 가장 큰 key를 best에 저장하고, 그 item(키 + 벨류)을 pop해서 꺼내줍니다.

    total 딕셔너리는 최종적으로 빈 딕셔너리 {} 가 됩니다.

     

    각 best(키)마다 순서대로 해당하는 노래의 고유 번호를 answer에 넣어줍니다.

     

    장르별 곡이 1곡일 때와 아닐 때(2곡 이상일 때)로 나눠주었습니다.

    2곡 이상일 때에는 곡별 재생횟수가 가장 많은 곡(혹은 두번째로 많은 곡)이 두 개 이상일 경우와 아닐 경우를 나눠주었습니다.

    최종적으로 곡별 재생횟수가 가장 많은 두 곡(겹칠시 고유번호가 가장 작은 두 곡)을 answer 리스트에 append하여 return해주었습니다..

sangilyoon.dev@gmail.com