Algorithm/프로그래머스

[프로그래머스] 방금그곡 (Java)

Carroti 2022. 11. 14. 12:08

문제

 

프로그래머스

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

programmers.co.kr

 

알고리즘

없음

 

풀이

재생된 시간만큼 musicinfo의 악보를 확장하여 멜로디 m이 포함되어있는지 확인하면 된다.

하지만 악보에 사용되는 음이 C, C# 처럼 #이 붙은 음이 있어 ABC#이라는 악보와 ABC라는 멜로디가 있다면 ABC#에 ABC가 포함된 것으로 잘못된 결과가 나올 수 있다.

 

따라서 이를 해결하기 위해 #이 들어간 음을 다른 문자로 변경하였다.

C# - 3, D# - 4, F# - 6, G# - 7, A# - 1

이 방법으로 ABC# 은 AB3 이 되고, ABC 라는 멜로디와 구분될 수 있다.

 

1. 멜로디 m의 #을 숫자로 변환

2. 음악이 재생된 시간 계산

3. 악보의 #을 숫자로 변환

4. 악보를 재생된 길이만큼 확장

5. 확장시킨 악보에 변환된 m이 포함되어 있는지 확인


1. 멜로디 m의 #을 숫자로 변환

m의 각 글자를 탐색하며 해당 글자의 다음 글자가 #이라면 두 글자를 합쳐서

A#은 1로, C#은 3과 같은 형식으로 변환한다.

 

이때 문자열이 계속 수정되기 때문에 StringBuilder를 사용한다.


2. 음악이 재생된 시간 계산

StringTokenizer를 이용해 ":" 로 시간과 분을 구분하여

(시작시간 * 60 + 시작분) - (종료시간 * 60 + 종료분) 로 음악이 재생된 시간을 계산한다.


3. 악보의 #을 숫자로 변환

1과 동일하게 변환한다.


4. 악보를 재생된 길이만큼 확장

 

만약 재생된 길이가 17, 악보의 길이가 4라면 해당 악보가 4번 반복되고 악보의 첫 음이 재생될 것이다.

즉 (재생된 길이 / 악보의 길이) 번 악보를 붙이고, (재생된 길이 % 악보의 길이) 글자만큼 추가로 붙이면

확장된 악보를 얻을 수 있다.


5. 확장시킨 악보에 변환된 m이 포함되어 있는지 확인

 

확장시킨 악보에 변환된 m이 포함되어있는지 확인하는데 StringBuilder는 contains() 메소드가 없기 때문에 대신 indexOf() 메소드를 사용한다.

indexOf(string)은 string이 있다면 index를, 없다면 -1을 반환한다.

 

따라서 악보.indexOf(멜로디)의 반환값이 -1이 아니고 재생 시간이 최대 재생 시간보다 길다면

정답과 최대 재생 시간을 갱신한다.

 

* 일치하는 음악이 없으면 "(None)" 을 반환해야하므로 answer를 "(None)"으로 초기화해둔다.

 

 

코드

import java.util.*;

class Solution {
    public String solution(String m, String[] musicinfos) {
        String answer = "(None)";
        int answerTime = 0;
        StringBuilder conM = convert(m);
        
        for(String musicinfo: musicinfos) {
            StringTokenizer st = new StringTokenizer(musicinfo, ",");
            
            int time = getTime(st.nextToken(), st.nextToken());
            String title = st.nextToken();
            StringBuilder acbo = convert(st.nextToken());
            StringBuilder extAcbo = extend(acbo.toString(), time);
            
            if(extAcbo.indexOf(conM.toString()) != -1 && time > answerTime) {
                answer = title;
                answerTime = time;
            }
        }
        return answer;
    }
    
    public int getTime(String start, String end) {
        StringTokenizer st = new StringTokenizer(start, ":");
        int startm = Integer.parseInt(st.nextToken()) * 60 + Integer.parseInt(st.nextToken());
        
        st = new StringTokenizer(end, ":");
        int endm = Integer.parseInt(st.nextToken()) * 60 + Integer.parseInt(st.nextToken());
        
        return endm - startm;
    }
    
    public StringBuilder convert(String string) {
        
        StringBuilder sb = new StringBuilder();
        for(int i=0; i<string.length(); i++) {
            if(i < string.length()-1 && string.charAt(i + 1) == '#') {
                sb.append((char)(string.charAt(i) - 'A' + '1'));
                i++;
            }
            else sb.append(string.charAt(i));
        }
        return sb;
    }
    
    public StringBuilder extend(String string, int time) {
        
        StringBuilder sb = new StringBuilder();
        for(int i=0; i<time/string.length(); i++)
            sb.append(string);
            
        for(int i=0; i<time%string.length(); i++)
            sb.append(string.charAt(i));
        
        return sb;
    }
}