파이썬 알고리즘 : 방금그곡

카카오 코딩테스트

2024년 3월 5일 알고리즘 문제풀이

문제

난이도

Lv.2

코드

언제나 카카오 문제는 일단 문제 이해가 힘들다.

1차

62.9/100 점

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
def solution(m, musicinfos):
    # 정답 음악 제목
    answer = ''
    # 정답 음악이 라디오에서 재생된 시간
    answer_t = 0
    
    for x in musicinfos:
        # 시작 시간, 종료 시간, 음악 제목, 악보
        start,end,title,content = x.split(",")
        # 시작 시와 분
        start_h, start_m = start.split(":")
        # 종료 시와 분
        end_h, end_m = end.split(":")
        # 재생된 시간 계산
        playtime = 60*(int(end_h)-int(start_h)) + (int(end_m) - int(start_m))
        # 악보를 list화
        tmp = list(content)
        
        # 재생된 시간이 악보보다 길다면, 악보를 반복한다.
        while len(tmp) < playtime:
            tmp += list(content)
            
        # 가장 처음부터 len(m)글자씩 보기 위한 반복
        for i in range(len(tmp)-len(m)):
            # i번째글자부터 i+m번째 글자까지 합쳐, 길이가 m과 같은 글자를 만든다
            k = "".join(tmp[i:i+len(m)])
            if k == m:
                # 만든 글자가 m과 같지만, 맨마지막에 #이 온다면 정답이 아니다.
                # "ABC" 를 찾았지만 악보상 "ABC#"으로 되어있다면 찾은 것으로 되겠지만 실제론 찾은게 아니기 때문
                # 첫번째 조건문은 그 다음이 #인지 확인할 때, 그 다음이 없을 경우를 위한 설정
                if i+len(m)+1 < len(tmp) and tmp[i+len(m)] != "#":
                    # 처음으로 찾은 음악이라면 정답으로 설정
                    if not answer_t:
                        answer = title
                        answer_t = playtime
                    # 이미 찾은 음악이 있다면, 재생된 시간이 더 길 때만 업데이트한다.
                    # 짧다면 업데이트할 필요가 없다.
                    # 같다면 이미 찾은 음악이 더 먼저 재생되었기 때문에 업데이트할 필요가 없다.
                    else:
                        if answer_t < playtime:
                            answer = title
    return answer

진짜 너무 복잡하다.. 풀면서도 이게 정답일 것 같지는 않다고 느꼈는데 역시나였다. 조건을 단순화해야한다. #이 붙었을 때를 제대로 처리하지 않은게 문제인듯 하다.

2차

77/100

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
def solution(m, musicinfos):
    
    def seperate(content):
        arr = []
        idx = 0
        while idx+1 < len(content):
            if content[idx+1] == '#':
                arr.append(content[idx]+content[idx+1])
                idx += 2
            else:
                arr.append(content[idx])
                idx += 1
        if content[-1] != "#":
            arr.append(content[-1])
        return arr
    
    def check(a,b):
        A = len(a)
        B = len(b)
        idx = 0
        while idx+B < A:
            if b == a[idx:idx+B]:
                return True
            else:
                idx += 1
    
    
    answer = ''
    answer_t = 0
    m = seperate(m)
    
    for x in musicinfos:
        start,end,title,content = x.split(",")
        start_h, start_m = start.split(":")
        end_h, end_m = end.split(":")
        playtime = 60*(int(end_h)-int(start_h)) + (int(end_m) - int(start_m))
        tmp = seperate(content)
        
        while len(tmp) < playtime:
            tmp += seperate(content)
        if check(tmp,m):
            if not answer_t:
                answer_t = playtime
                answer = title
            else:
                if answer_t < playtime:
                    answer = title
                    answer_t = playtime     

    return answer

애초에 리스트로 만들때, #이 붙은 녀석을 한꺼번에 처리하려고 노력했다. 따로 비교하는 함수도 만들었지만 여전히 실패한다. 아예 지우고 처음부터 다시 생각해 보는게 더 빠른 해결책일 듯 하다.

3차

88.6/100

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
def solution(m, musicinfos):
    answer = ""
    answer_t = 0
    def change(l):
        l = l.replace('A#', 'H')
        l = l.replace('B#', 'I')
        l = l.replace('C#', 'J')
        l = l.replace('D#', 'K')
        l = l.replace('F#', 'L')
        l = l.replace('G#', 'M')
        return l
    m = change(m)
    
    for x in musicinfos:
        start,end,title,content = x.split(",")
        content = change(content)
        start_h, start_m = start.split(":")
        end_h, end_m = end.split(":")
        playtime = 60*(int(end_h)-int(start_h)) + (int(end_m) - int(start_m))
        if playtime > len(content):
            content = content*(playtime//len(content)) + content[:playtime%len(content)]
        else:
            content = content[:playtime]
        if m in content:
            if not answer_t:
                answer_t = playtime
                answer = title
            else:
                if answer_t < playtime:
                    answer = title
                    answer_t = playtime     

    return answer

샵이 붙은것과 안붙은 것을 구분하기 위해, 붙은 것을 아예 새로운 알파벳으로 치환해버렸다. 훨씬 비교가 단순해졌다. 기존에는 음악이 반복되더라도 꼭 끝까지 다 재생되는 것으로 생각했는데 그 부분도 시간에 맞게 연주되고 끊기도록 변경했다. 딱 4개의 예외 케이스가 존재하는 것 같은데..

최종

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
def solution(m, musicinfos):
    def change(l):
        l = l.replace('A#', 'H')
        l = l.replace('B#', 'I')
        l = l.replace('C#', 'J')
        l = l.replace('D#', 'K')
        l = l.replace('F#', 'L')
        l = l.replace('G#', 'M')
        return l
    
    answer = "(None)"
    answer_t = 0
    # 비교군도 변환해야함
    m = change(m)
    
    for x in musicinfos:
        start,end,title,content = x.split(",")
        content = change(content)
        start_h, start_m = start.split(":")
        end_h, end_m = end.split(":")
        playtime = 60*(int(end_h)-int(start_h)) + (int(end_m) - int(start_m))
        
        # 음악의 길이보다 재생시간이 길면 반복한다.
        if playtime > len(content):
            content = content*(playtime//len(content)) + content[:playtime%len(content)]
        else:
            content = content[:playtime]
        
        if m in content:
            if not answer_t:
                answer_t = playtime
                answer = title
            else:
                if answer_t < playtime:
                    answer = title
                    answer_t = playtime     

    return answer

문제를 잘 읽자. 없을떄는 “(None)” 을 반환한하란다.