Algorithm

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

랩실외톨이 2023. 9. 16. 04:22
반응형

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

 

프로그래머스

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

programmers.co.kr

 

1. 서론

 

풀다가 돌 뻔했으나 그렇게 어렵지는 않은 문제. 근데 사실 그 방법을 떠올리는 게 어렵다.

특히 tc 3,4,6,7,8,9,12,15,18,19 틀린 분들 주목하세요.

 

2. 문제 풀이

 

쉽게 설명하자면 이런 문제다. musicinfos에 '음악 재생 시작 시간', '음악 재생 끝난 시간', '음악 제목', '악보'가 주어진다.

그럼 이 악보를 탐색하면서 m에 있는 문자열이 나오는지를 판단하는 문제다.

 

근데 제약조건이 많고 이걸 다 충족 시켜야만 한다.

 

1. 음악은 반드시 처음부터 재생

1-1. 음악 길이 < 재생시간 : 끊임없이 처음부터 반복 재생

1-2. 음악 길이 > 재생시간: 처음부터 재생 시간만큼만 재생

 

2. 음악은 00:00 ~23:59 하루 범위 안에만 나옴

 

3-1. 조건이 일치하는 음악이 여러 개일 경우 -> 재생 시간이 가장 긴 음악

3-2. 재생 시간도 같을 경우 -> 먼저 입력된 음악

3-3. 조건이 일치하는 음악이 없을 때 -> (None)

 

4. 악보에 사용되는 음: C, C#, D, D#, E, F, F#, G, G#, A, A#, B 

 

 

 

반응형

 

 

 

 

대부분의 사람들은 당연히 이 조건들을 다 맞췄다고 생각하고 제출한다. 그러면 수많은 테케를 틀리게 된다.... 제가 문제를 맞은 비법을 공해합니다.

 

일단 가장 크게 놓친 조건은 4번이었다. 그냥 별로 신경을 안 썼다. 저런 게 있구나... 근데 문제는 '#'이었다. 다른 건 그냥 알파벳 단위라 비교하면 그만인데 #이 붙은 것은 그 두 개의 문자가 한 단위였기 때문이다. 그래서 질문하기를 열심히 뒤진결과 'X#' 이 조건을 그냥 다른 문자로 교체시키자 아마 6,7,8,9,12,15 tc가 해결됐다.

 

그리고 틀린걸 고치느라 1-2. 의 조건인 '처음부터 재생 시간만큼만 재생'을 처음엔 재생시간만큼 했다가 주어진 악보를 그냥 return 했더니 4번은 맞고 30번은 틀린 것으로 처리됐다.

1-2. 의 조건도 맞춰주자 드디어 다 맞았다...

 

 

 

 

반응형

 

 

 

 

 

3. 코드 설명

 

import java.util.*;

class Solution {
    public String solution(String m, String[] musicinfos) {
        String answer = "";
        m = change(m);
        String[][] infos = new String[musicinfos.length][4];
        for (int i = 0; i < musicinfos.length; i++) {
            StringTokenizer st = new StringTokenizer(musicinfos[i], ",");
            for (int j = 0; j < 4; j++) {
                infos[i][j] = st.nextToken();
                if (j == 3)
                    infos[i][j] = change(infos[i][j]);
            }
        }
        
        int[] size = new int[musicinfos.length];
        for (int i = 0; i < musicinfos.length; i++) {
            String s1 = infos[i][0];
            int h1 = calc(s1.substring(0, 2));
            int m1 = calc(s1.substring(3, 5));
            
            String s2 = infos[i][1];
            int h2 = calc(s2.substring(0, 2));
            int m2 = calc(s2.substring(3, 5));
            size[i] = ((h2 - h1) * 60) + m2 - m1;
        }
        
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < musicinfos.length; i++) {
            String s = cut(infos[i][3], size[i]);
            for (int j = 0; j <= s.length() - m.length(); j++)
                if (m.equals(s.substring(j, j +  m.length())))
                    list.add(i);
        }
        
        if (list.isEmpty())
            answer = "(None)";
        else if (list.size() > 1) {
            int max = 0, idx = 0;
            for (int i = 0; i < list.size(); i++) {
                int x = list.get(i);
                if (size[x] > max) {
                    max = size[x];
                    idx = x;
                }
            }
            
            answer = infos[idx][2];
        }
        else if (list.size() == 1)
            answer = infos[list.get(0)][2];
        
        return answer;
    }
    
    public String cut(String s, int n) {
        if (n <= s.length())
            return s.substring(0, n);
        else {
            String t = "";
            for (int i = 0; i < n / s.length(); i++)
                t += s;
            
            int x = n % s.length();
            if (x != 0)
                t += s.substring(0, x);
              
            return t;
        }
    }
    
    public String change(String s) {
        s = s.replace("C#", "c");
        s = s.replace("D#", "d");
        s = s.replace("F#", "f");
        s = s.replace("G#", "g");
        s = s.replace("A#", "a");
        
        return s;
    }
    
    public int calc(String s) {
        return Integer.parseInt(s);
    }
}

 

주어진 musicinfos를 '음악 재생 시작 시간', '음악 재생 끝난 시간', '음악 제목', '악보'로 쪼개서 꺼내 쓰기 쉽게 잘라서 배열로 만들었다.

그 과정에서 문자열들을 치환했는데 이때 놓치기 쉬운 게 m은 치환을 안 했다가 치환했는데 왜 틀려! 이렇게 성냈다 ㅎ

 

그리고 음악 재생시간은 size라는 배열에 따로 계산해서 담아줬다.

그리고 재생시간에 맞춰서 악보를 붙이고 잘라서 재조정한 문자열을 m의 길이만큼 계속 잘라서 비교해 줬다.

 

이때 같은 값이 여러 개 일 수 있기 때문에 조건에 맞는 것은 다 list에 넣었다.

list에 담긴 값이 0이면 (None)

1이면 그게 답

1 이상이면 음악 재생시간의 max를 찾아준다. 이때 계속 값을 경신하면서 max와 같을 때의 값을 처리 안 하면 입력 순서대로 처리하는 조건을 충족할 수 있다.

 

 

반응형