프로그래머스 Lv3. 베스트앨범

Tabber·2021년 6월 11일
0

알고리즘

목록 보기
3/4

문제 설명

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

  • 속한 노래가 많이 재생된 장르를 먼저 수록합니다.
  • 장르 내에서 많이 재생된 노래를 먼저 수록합니다.
  • 장르 내에서 재생 횟수가 같은 노래 중에서는 고유 번호가 낮은 노래를 먼저 수록합니다.

노래의 장르를 나타내는 문자열 배열 genres와 노래별 재생 횟수를 나타내는 정수 배열 plays가 주어질 때, 베스트 앨범에 들어갈 노래의 고유 번호를 순서대로 return 하도록 solution 함수를 완성하세요.

제한사항

  • genres[i]는 고유번호가 i인 노래의 장르입니다.
  • plays[i]는 고유번호가 i인 노래가 재생된 횟수입니다.
  • genres와 plays의 길이는 같으며, 이는 1 이상 10,000 이하입니다.
  • 장르 종류는 100개 미만입니다.
  • 장르에 속한 곡이 하나라면, 하나의 곡만 선택합니다.
  • 모든 장르는 재생된 횟수가 다릅니다.

문제의 이해

요즘 코딩테스트 공부를 하며 느낀거지만, 문제를 잘 이해해야 뭐라도 보이는 것 같다.
사실 국어 공부랑 같이 하는 느낌인데 (수학공부도,,) 위 문제를 살펴보자.

위 문제에서 말하는 기준으로 각 장르에서 대표하는 노래 2개씩을 추출하라는 소리로 이해했다. 사실 지문에서는 2+2 = 4 개 를 출력하라는 말이 나오지 않았지만, 사실 예제나, 여러 테스트 케이스에서 설명하길, 각 장르에서 대표 2곡을 출력하라는 말과 같다고 한다.

문제의 풀이

일단 [장르] 와 [플레이] 리스트가 따로 나누어져 있길래 두개를 묶어야 나중에 계산할때 편할 것이라는 생각을 해서 둘을 합친 리스트를 추가했다.

그 후에는 일단 무슨 장르가 존재하는지에 대해 알아야 하니, 중복된 장르들을 필터링 하고, 각 장르들에 대한 총합을 같이 넣어줬다. 그래야지 위에서 설명해준 기준에 맞게 정렬할 수 있기 때문이다.

그 후에는 아까 장르와 플레이를 합친 리스트도 나머지 기준으로 정렬을 해줬다.
그리고 최종적으로 중복을 제거해준 리스트를 하나씩 불러오면서 그 장르에 맞는 가장 높은 횟수의 인덱스를 2개씩 불러와 답 리스트에 넣어줬다.

글로 이렇게 얘기하면 이해가 잘 안갈것이다. 코드를 보자.

코드(주석 있습니다)

def solution(genres, plays):
    answer = []     # 답 리스트
    board = []      # 수록하는 기준대로 저장하는 리스트
    board_name = {} # 중복되는 이름 제거한 딕셔너리
    
    # 첫 번째 for 문
    # 먼저 board에 [['장르', 재생된 횟수], 인덱스] 순으로 한번에 묶어서 리스트를 생성
    index = 0 # 고유 인덱스
    for name, play in zip(genres, plays):
        board.append(([name,play], index))
        index += 1
        board_name[name] = 0
        
        
    # 두 번째 for 문
    # 람다식으로 처리가 가능하겠지만, 람다식이 미숙하여 for문으로 처리
    # 딕셔너리에 저장된 장르들의 총 재생된 횟수를 for문으로 돌며 처리
    for i in board:
        board_name[i[0][0]] = board_name[i[0][0]] + i[0][1]
    
    
    # 재생된 횟수 기준으로 많은 횟수부터 차례대로 정렬
    board_name = sorted(board_name.items(),reverse=True, key=lambda x:x[1])
    
    # 문제에서 설명한 기준대로 정렬
    board.sort(reverse=True, key=lambda x: ((x[0][1]), -x[1]))
    
    # board_name과 board는 다른 리스트입니다. (심지어 board_name은 딕셔너리로 시작)
    
    
    # 마지막 for 문
    # board_name 리스트에 저장된 중복을 뺀 이름들을 차례대로 불러온다.
    # 이미 횟수 기준으로 정렬이 되어있는 상태라 가져와서 사용하면 된다.
    
    # 중첩 for문을 돌려 가져온 이름에 해당하는 인덱스를 answer에 추가시켜준다.
    # 이때 각 리스트에서 2개씩 가져온다.
    for key in board_name:
        num = 0
        key_name = key[0]
        for i in range(len(board)):
            if board[i][0][0] == key_name:
                if num == 2:
                    break
                answer.append(board[i][1])
                num += 1
    
    return answer

주석을 열심히 달긴했는데 혹시라도 모르는 사람이 있다면 보고 이해가 가길 바란다.
코드가 난잡하다. (하지만 본인은 통과된 것 만으로도 만족하기 때문에..)

문제를 풀고 배운점

람다식을 어느정도 사용할 수 있게 됐다. (아 물론 정렬할때만..)
람다식이 엄청 편하고 실용적인 것 같다. 하지만 아직 익숙하지가 않아서 걱정이다. 많이 사용해봐야 할텐데..
점점 내 힘으로 풀 수 있는 문제들이 생겨난다. 정말 다행이다. 그래도 뭔가를 했다라는 생각이 들게끔 해준다. 더 열심히 하면 더 잘해낼수 있지 않을까? 라는 생각도 든다. 하지만 태생이 귀차니즘인 나를 막을순 없는 듯 하다.

profile
iOS 정복중인 Tabber 입니다.

0개의 댓글