[문자열] PRG 17683: 방금그곡

KimRiun·2021년 11월 6일
0

알고리즘_문제

목록 보기
18/26

사용 언어: python 3.9.5

❓ Problem

문제 설명

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

난이도

levle 2

🚩 Solution

시도 01)

1. 접근법

음계를 저장하는 딕셔너리 melody를 활용한다.

이때 '#'이 붙은 음들은 '#'이 붙지 않은 다른 알파벳으로 바꾼다.

  1. 전처리

    m과 musicinfos의 악보 sheet를 딕셔너리 melody에 맞게 음을 변환한다.

    m과 sheet를 전처리하여 각각 newM과 newSheet에 저장한다.

  2. newSheet를 재생 시간만큼 반복한 문자열 newSheet2를 구한다.

  3. newM이 newSheet2에 있는지 검사하고, 정답을 구한다.

2. 코드

import collections
def solution(m, musicinfos):
    melody = collections.defaultdict(str)
    # 런타임 에러: 'E#'이 문제에 없는데 'E#'을 넣어야 테스트 27번 통과됨. 문제가 잘못됨. 와중에 'B#'은 없음
    # '#'이 있는 음들은 '#'이 아닌 다른 알파벳으로 바꾼다
    melody = {'C':'C', 'C#':'H', 'D':'D', 'D#':'I', 'E':'E', 'F':'F', 'F#':'J', 'G':'G', 'G#':'K', 'A':'A', 'A#':'L', 'B':'B', 'E#':'M' }

    ### '#'이 있는 음을 melody 딕셔너리에 맞게 변환 
    i = 0
    newM = ''
    while(i < len(m) - 1):
        if m[i+1] == '#':
            newM += melody[m[i] +'#']
            i += 2
        else:
            newM += melody[m[i]]
            i += 1
    # 런타임 에러: 마지막이 '#'일 때 처리를 빼먹어서 틀렸음
    if(m[-1] != '#'):
        newM += melody[m[-1]]

    ### musicinfos의 원소들 하나씩 검사
    answer = ''
    longLength = 0
    for music in musicinfos:
        # 전처리
        parse = music.split(',')

        # 런타임 에러: 분은 계산했는데 시간을 계산안했었다
        time = (int(parse[1][0:2]) - int(parse[0][0:2]))*60 + (int(parse[1][3:5]) - int(parse[0][3:5]))

        title = parse[2]
        sheet = parse[3] # 원본 악보
 
        ### 원본 악보에서 '#'이 있는 음을 melody 딕셔너리에 맞게 변환 
        newSheet = '' 
        i = 0
        while(i < len(sheet) - 1):
            if sheet[i+1] == '#':
                newSheet += melody[sheet[i] +'#']
                i += 2
            else:
                newSheet += melody[sheet[i]]
                i += 1
        # 런타임 에러: 마지막이 '#'일 때 처리를 빼먹어서 틀렸음
        if(sheet[-1] != '#'):        
            newSheet += melody[sheet[-1]]
        

        ### 시간만큼 반복해서 음을 연결함
        i = 0
        newSheet2 = ''
        for i in range(time):
            newSheet2 += newSheet[i%len(newSheet)]

        ### 더 시간이 긴 정답이 있으면 정답 갱신
        if newM in newSheet2:
            if longLength < time:
                answer = title
		longLength = time
    
    if answer == '':
        answer = "(None)" # 런타임 에러: "(None)"을 그냥 None으로 넣어서 틀렸음

    return answer

3. 시간복잡도

O(n)O(n)

4. 결과

성공

메모리: 20000 KB

시간: 116 ms

5. 소요 시간

1시간 이상

📕 피드백

1. 검색한 내용

2. 실수

3. 발전 방향 (개선/추가사항)

단순 변환이기 때문에 딕셔너리대신 replace() 함수를 썼으면 시간이 훨씬 단축됐을 것이다.

단순 변환은 replace()를 활용하자.
변형한 코드

def no_shap(s):
    s = s.replace('C#','H').replace('D#', 'I').replace('F#','J').replace('G#','K').replace('A#','L').replace('E#','M')
    return s

def solution(m, musicinfos):
    m = no_shap(m)

    answer = ''
    longLength = 0
    for music in musicinfos:
        # 전처리
        parse = music.split(',')
        time = (int(parse[1][0:2]) - int(parse[0][0:2]))*60 + (int(parse[1][3:5]) - int(parse[0][3:5]))
        title = parse[2]
        sheet = no_shap(parse[3]) # 원본 악보 -> '#' 없음

        ### 시간만큼 반복해서 음을 연결함
        fullSheet = ''
        for i in range(time):
            fullSheet += sheet[i%len(sheet)]

        ### 더 시간이 긴 정답이 있으면 정답 갱신
        if m in fullSheet:
            if longLength < time:
                answer = title
                longLength = time
    
    if answer == '':
        answer = "(None)" 

    return answer

print(solution("ABC",["12:00,12:14,HELLO,C#DEFGAB", "13:00,13:05,WORLD,ABCDEF"]))

4. 다른 사람 풀이

풀이1)

  • 접근법

'#'이 붙은 음들을 처리하고, 재생 시간만큼 음들을 이어 붙인다는 풀이 방식은 같음

  • 코드
def shap_to_lower(s):
    s = s.replace('C#','c').replace('D#','d').replace('F#','f').replace('G#','g').replace('A#','a')
    return s

def solution(m,musicinfos):
    answer=[0,'(None)']   # time_len, title
    m = shap_to_lower(m)
    for info in musicinfos:
        split_info = info.split(',')
        time_length = (int(split_info[1][:2])-int(split_info[0][:2]))*60+int(split_info[1][-2:])-int(split_info[0][-2:])
        title = split_info[2]
        part_notes = shap_to_lower(split_info[-1])
        full_notes = part_notes*(time_length//len(part_notes))+part_notes[:time_length%len(part_notes)]
        if m in full_notes and time_length>answer[0]:
            answer=[time_length,title]
    return answer[-1]
  • 배울 점
  1. replace()함수를 통해 '#'이 붙은 음들을 처리함.

    → 나는 딕셔너리를 썼는데, 단순 변환이면 replace()가 더 좋겠다.

  2. replace()가 반복되는 과정을 함수로 만들었음.

    → 나는 반복되는 while문이 많아서 가독성이 떨어졌는데, 함수를 사용하면 더 좋겠다.

  3. 시간을 구할 때, [:2] 또는 [-2:] 방식으로, 인덱스로 [0:3] 이렇게 직접 접근하는 것보다 파이썬스럽게 문자열을 슬라이싱함.

    [a:], [:b] 잘 활용하자

  4. 문자열을 이어 붙일 때, 연산자 * , // , % 를 잘 활용함.

    → 문자열 연산자 * 를 잘 활용하자

  5. shar_to_lower, split_info, part_notes , full_notes 등 변수명을 잘 지었음.

profile
Java, Python

0개의 댓글