알고리즘 문제/프로그래머스

프로그래머스 [3차] 방금 그 곡

PureStack 2021. 11. 2. 19:13

문제 링크: https://programmers.co.kr/learn/courses/30/lessons/17683

입력

m: 네오가 기억한 멜로디를 담은 문자열, musicinfos: 방송된 곡의 정보를 담고 있는 배열

  • m: 음 1개 이상 1439개 이하로 구성
  • musicinfos: 100개 이하의 곡 정보를 담고 있는 배열, 각각의 곡 정보는 음악이 시작한 시각, 끝난 시각, 음악 제목, 악보 정보
    • 각각의 정보는 ','로 구분
    • 음악 시작 시각과 끝난 시각은 24시간 HH:MM 형식
    • 음악 제목은 ',' 이외의 출력 가능한 문자로 표현된 길이 1이상 64 이하의 문자열
    • 악보 정보는 음 1개 이상 1439 개 이하로 구성

출력

조건과 일치하는 음악 제목을 출력한다.

해결 방법

1. 입력 데이터 치환
문자열 m과 musicinfos 배열에서 악보 정보의 문자열에서 #이 붙은 멜로디를 소문자로 치환한다. 예를 들어, C#을 소문자 c로 대체한다.
Java의 경우네느 replace를 이용하여 문자열을 치환한다.

private static String replaceMelody(String str) { //멜로디 문자열을 치환

        for(int i=0;i<str.length();i++) {
            str = str.replace("A#", "a"); //Java의 문자열 치환 함수 replace 이용
            str = str.replace("C#", "c");
            str = str.replace("D#", "d");
            str = str.replace("F#", "f");
            str = str.replace("G#", "g");
        }

        return str;
}

2. 총 재생 시간 계산
musicinfos의 배열에서 시작 시간과 종료 시간을 이용해서 총 재생 시간을 계산한다. Java의 경우, 시작 시간과 종료 시간 각각 ":"을 기준으로 문자열을 split 함수로 쪼개서, 배열을 만든다. 이후, 각각을 초단위로 변환한 이후, 종료 시간에서 시작 시간을 빼서 총 재생 시간을 구한다.

private static int getMusicTime(String start, String end) { //총 재생 시간 계산
        String[] startTime = start.split(":"); //start 문자열을 ":"를 기준으로 split 하여 배열을 형성
        String[] endTime = end.split(":");

        int begin = Integer.parseInt(startTime[0])*60 + Integer.parseInt(startTime[1]); // 초 단위로 변환
        int finish = Integer.parseInt(endTime[0])*60 + Integer.parseInt(endTime[1]);

        return finish-begin; //총 재생 시간 계산
}

3. 재생 시간만큼 음악을 반복
우선 StringBuilder 객체를 생성한 후, 재생 시간만큼 반복하여 악보를 이어 붙인다. 이때 StringBuilder의 append 함수를 이용하여 문자열을 추가하고, 이 객체를 String으로 변환한다.

StringBuilder sb = new StringBuilder();

for(int j=0;j<musicTime;j++) { //재생 시간만큼 반복
            int idx = j%info[3].length(); // 반복 인자 j를 악보 길이만큼 나누어서 인자를 구함

            sb.append(info[3].charAt(idx)); // info[3] 문자열에서 위에서 구한 인자에 해당하는 문자를 더함
}

String lyrics = sb.toString(); // StringBuilder를 String으로 변환

4. 정답 구하기
만들어진 멜로디 문자열에서 네오가 기억한 문자열 m이 포함되어 있는지 찾는다. 만약 여러 개라면 재생 시간이 가장 긴 것으로 갱신한다.
만약에 조건에 만족하지 않으면 "none" 반환

if(lyrics.contains(m)) { //멜로디 포함 여부 확인
        if(time < musicTime) { // 재생 시간 긴 여부 확인
                time = musicTime; //재생 시간이 가장 긴 것으로 갱신
                answer = info[2];
        }
}

전체 코드

class Solution {
    public String solution(String m, String[] musicinfos) {
        String answer="(None)";
        int time = 0;

        m = replaceMelody(m);

        for(int i=0;i<musicinfos.length;i++) {
            String[] info = musicinfos[i].split(",");
            info[3] = replaceMelody(info[3]);

            int musicTime = getMusicTime(info[0], info[1]);

            StringBuilder sb = new StringBuilder();

            for(int j=0;j<musicTime;j++) {
                int idx = j%info[3].length();

                sb.append(info[3].charAt(idx));
            }

            String lyrics = sb.toString();

            if(lyrics.contains(m)) {
                if(time < musicTime) {
                    time = musicTime;
                    answer = info[2];
                }
            }

        }

        return answer;
    }

    private static String replaceMelody(String str) {

        for(int i=0;i<str.length();i++) {
            str = str.replace("A#", "a");
            str = str.replace("C#", "c");
            str = str.replace("D#", "d");
            str = str.replace("F#", "f");
            str = str.replace("G#", "g");
        }

        return str;
    }

    private static int getMusicTime(String start, String end) {
        String[] startTime = start.split(":");
        String[] endTime = end.split(":");

        int begin = Integer.parseInt(startTime[0])*60 + Integer.parseInt(startTime[1]);
        int finish = Integer.parseInt(endTime[0])*60 + Integer.parseInt(endTime[1]);

        return finish-begin;
    }
}