프로그래머스

LV2 [KAKAO] [3차] 방금그곡

whiporithm 2023. 8. 17. 12:35


문제

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

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

풀이

 

(해당 풀이는 처음 풀었을때의 풀이고, 뒤에 훨씬 간단한 개선 풀이 코드가 있음)

 

  1. 문자열로 들어온 시간을 파싱해서 노래의 재생시간(runningTime)을 구했다. 
    • 처음에는 단순히 int로 바꾼다음 끝나는 시간에서 시작시간을 빼면 될거라 생각했으나 "13:50 ~ 14:10" 처럼 끝나는 시간의 '분' 이 더 앞설때 처리하기가 까다로워 datetime 을 활용하여 처리했다.
  2. completeNote 구하기
    • 음악의 악보가 ABC#D 이고, 재생시간이 6일때 실제로 재생된 악보는 ABC#DAB 이다.
    • 재생시간만큼 악보의 한 음에 접근하면서 결과적으로 재생된 악보를 만든다.
    • # 이 붙은 음들은 따로 예외처리를 해준다. 
      • 우선 범위 검사랑, 알파벳 뒤에 #이 있는지 항상 검사한다.
      • 만약 #이 있다면 #을 포함해서 completeNote에 추가해주고, 인덱스도 두 칸 뛰어 넘는다.
  3. 배열로 만들기
    • 내가 들은 음과, completeNote를 비교하기 편하게 배열로 만들어준다.
    • completeNote에서 처리한 거 처럼 알파벳 뒤에 #이 있는지 항상 검사해주고 있으면 인덱스를 두 칸 씩 넘는다.
  4. 비교하기
    • completeNote 배열을 순회하다가, 내가 들은 음의 첫번째 음과 같은 음이 나온다면, 그 때부터 내가 들은 음과 반복적으로 비교해준다.
      • ex> 내가 들은 음이 ABC, completeNote가 BCABC 일 경우, completeNote[2] => A , 여기서부터 ABC가 존재하는지 검사한다.
      • 만약 비교중간에 completeNote 끝에 도달해서 더 비교할 수 없거나, 또는 중간에 비교값이 다르다면 반복문을 탈출한다.
      • 중간에 탈출하지 않았더라면, 비교값이 모두 같다는 뜻이므로 기존의 재생시간보다 긴 지 확인하고 갱신해주면 된다. (재생시간의 초기값은 -1로 설정했다.)

 

코드 

from datetime import datetime
import time

def parsing_M(m):
    m_arr = []
    i = 0
    while True:
        if i>= len(m): break
        if i+1 < len(m) and m[i+1] == '#':
            m_arr.append(m[i] + m[i+1])
            i += 2
            continue
        m_arr.append(m[i])
        i+=1
    return m_arr

def makeCompleteNote(runningTime, note):
    completeNote = ''
    idx = 0
    for _ in range(runningTime):
        if idx + 1 < len(note) and note[idx+1] == '#':
            completeNote += (note[idx] + note[idx+1])
            idx += 2
        else:
            completeNote += note[idx]
            idx += 1
        if idx >= len(note): idx = 0
    return completeNote

def get_minutes(td):
    return (td.seconds//3600 * 60) + ((td.seconds//60)%60)

def solution(m, musicinfos):
    targetSong = '(None)'
    targetTime = -1
    
    for music in musicinfos:
        start, end, name, note = music.split(',')
        runningTime = int(get_minutes(datetime.strptime(end, '%H:%M') - 
                                      datetime.strptime(start, '%H:%M')))
        
        completeNote = makeCompleteNote(runningTime, note)
        m_arr = parsing_M(m)
        c_arr = parsing_M(completeNote)
        
        for i in range(len(c_arr)):
            if c_arr[i] == m_arr[0]:
                possible = True
                for j in range(len(m_arr)):
                    if i+j >= len(c_arr): 
                        possible = False
                        break
                    if c_arr[i+j] != m_arr[j]: 
                        possible = False
                        break
                
                if possible and runningTime > targetTime:
                    targetTime = runningTime
                    targetSong = name
                    
    return targetSong

 

후기

 

처음에는 그냥 completeNote를 만들고, 내가 들은 음이 completeNote에 있는지 검사하는 방식으로 했다.
그러나 # 처리를 전혀 생각하지 못했다. ABC# 이라는 재생악보에서 ABC가 있는지 검사하면 True가 나왔다. 단순히 문자열로 생각했으니 .. 당연하다.  결국 ABC# 과 ABC모두 각각 배열로 파싱해서 비교하는 방식으로 변경했다.

 

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

 

다른 코드를 보니 C#같은건 그냥 c로, D#은 d로 바꾸어서 처리했더라.
값을 치환했더라면 내가 처음에 생각했던  로직도 가능할 거 같아서 개선 코드를 작성해보았다.

 

from datetime import datetime

def get_minutes(td):
    return (td.seconds//3600 * 60) + ((td.seconds//60)%60)

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):
    targetSong = '(None)'
    targetTime = -1
    m = shap_to_lower(m)
    for music in musicinfos:
        start, end, name, note = music.split(',')
        runningTime = int(get_minutes(datetime.strptime(end, '%H:%M') - 
                                      datetime.strptime(start, '%H:%M')))
        note = shap_to_lower(note)
        completeNote = ''
        idx = 0
        for _ in range(runningTime) :
            completeNote += note[idx]
            idx += 1
            if idx >= len(note) : idx=0
        
        if m in completeNote and runningTime>targetTime:
            targetTime = runningTime
            targetSong = name
        
    return targetSong

 

인풋값을 바꾸는 생각의 전환도 필요해보인다.

'프로그래머스' 카테고리의 다른 글

LV3 [KAKAO] 보석 쇼핑  (0) 2023.08.21
LV3 [KAKAO] 불량 사용자  (0) 2023.08.18
LV2 [KAKAO] [1차] 캐시  (0) 2023.08.16
LV2 [KAKAO] [3차] 압축  (0) 2023.08.15
LV2 [KAKAO] 튜플  (0) 2023.08.14