[ 프로그래머스 ] 17683 방금그곡

codesver·2023년 8월 3일
0

Programmers

목록 보기
12/30
post-thumbnail

📌 Problem

재생된 음악의 대한 정보가 순서대로 제공된다. 각 음악의 대한 정보는 문자열 형태로 들어오는 데 시작시간, 종료시간, 제목, 멜로디가 문자 ,를 기준으로 구분되어 주어진다. (03:00,03:08,TITLE,MELODY) Melody는 총 12개의 음으로 이루어지는 데 각각 C, C#, D, D#, E, F, F#, G, G#, A, A#, B 이다. 각각의 음정을 재생하는 데에는 1분이 걸리며 재생시간 동안 멜로디는 반복재생된다. 즉, 멜로디가 DGG#이고 7분 동안 재생되었으면 재생된 음악은 DGG#DGG#D이다.
내가 듣고 기억한 멜로디가 주어졌을 때 해당 멜로디를 포함된 음악을 찾으면 된다. 예를 들어 직전의 예시에서 G#DGG#을 들었으면 해당 음악은 내가 들은 멜로디를 포함한 것이다. 이 때 만족하는 음악이 여러개 있을 경우 지속 시간이 가장 긴 음악의 제목을 반환한다. 지속시간이 동일하다면 먼저 주어진 음악의 제목을 반환한다.
다만, 맞는 음악이 없으면 "(None)"을 반환한다.

📌 Solution

우선 음악의 정보(시작 시간, 종료 시간, 총 재생된 멜로디, 주어진 순서)를 묶어서 생각한다. 이때 음정에서 #이 있으면 #을 제외하고 직전의 문자를 소문자로 만든다. 예를 들어 F#은 f으로 변환한다. 이는 이후에 문자열 매칭을 통해 확인하기 위해서이다. (만약 #을 제거하지 않으면 DGG#이라는 멜로디에는 DGG가 포함되게 된다.)
Filtering으로 통해 내가 들은 멜로디가 포함된 음악들을 찾아내고 그 중 최적의 음악을 찾아서 음악의 제목을 반환한다.

📌 Code

public String solution(String m, String[] musicInfos) {
    Optional<Music> heardMusic = IntStream.range(0, musicInfos.length)
            .mapToObj(index -> new Music(index, musicInfos[index]))
            .filter(music -> music.playedIntervalsIncludes(m))
            .max((preMusic, postMusic) -> {
                if (preMusic.duration() == postMusic.duration())
                    return postMusic.index - preMusic.index;
                else return (int) (preMusic.duration() - postMusic.duration());
            });
    return heardMusic.isPresent() ? heardMusic.get().title : "(None)";
}
class Music {

    final int index;
    final String title;
    final LocalTime start, end;
    final String playedIntervals;

    public Music(int index, String info) {
        this.index = index;

        String[] infos = info.split(",");

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm");
        start = LocalTime.parse(infos[0], formatter);
        end = LocalTime.parse(infos[1], formatter);

        title = infos[2];

        int playedTime = (int) (Duration.between(start, end).getSeconds() / 60);
        String intervals = changeSharpToSingleInterval(infos[3]);
        playedIntervals = intervals.repeat(playedTime / intervals.length())
                + intervals.substring(0, playedTime % intervals.length());
    }

    public boolean playedIntervalsIncludes(String intervals) {
        String s = changeSharpToSingleInterval(intervals);
        return playedIntervals.contains(s);
    }

    public long duration() {
        return Duration.between(start, end).getSeconds();
    }

    private String changeSharpToSingleInterval(String intervals) {
        StringBuilder changer = new StringBuilder(intervals);
        for (int i = 0; i < changer.length(); i++) {
            if (changer.charAt(i) == '#') {
                changer.setCharAt(i - 1, Character.toLowerCase(changer.charAt(i - 1)));
                changer.deleteCharAt(i--);
            }
        }
        return changer.toString();
    }
}
profile
Hello, Devs!

0개의 댓글