본문 바로가기

알고리즘

[2018 KAKAO BLIND RECRUITMENT] [3차] 방금그곡

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

 

코딩테스트 연습 - [3차] 방금그곡 | 프로그래머스

방금그곡 라디오를 자주 듣는 네오는 라디오에서 방금 나왔던 음악이 무슨 음악인지 궁금해질 때가 많다. 그럴 때 네오는 다음 포털의 '방금그곡' 서비스를 이용하곤 한다. 방금그곡에서는 TV, 라디오 등에서 나온 음악에 관해 제목 등의 정보를 제공하는 서비스이다. 네오는 자신이 기억한 멜로디를 가지고 방금그곡을 이용해 음악을 찾는다. 그런데 라디오 방송에서는 한 음악을 반복해서 재생할 때도 있어서 네오가 기억하고 있는 멜로디는 음악 끝부분과 처음 부분이 이어

programmers.co.kr

 

 

이 문제가 꽤 시간이 오래걸렸다. 간단한 문제였지만, 빨리 풀려는 마음에, 한 지문을 내마음대로 이해해버렸다. 아래 과정에서 설명하도록 하겠다.

 

 

 


 

 

문제를 풀기 위해서는, 재생된 시간을 맞춰서 멜로디를 늘려주거나 줄여주면 된다.

 

 

예를 들어서,

ABCDEFG [12:00,12:14,HELLO,CDEFGAB, 13:00,13:05,WORLD,ABCDEF]

 

 

CDEFGAB의 경우에는, CDEFGABCDEFGAB의 형태로 작성해주면 된다. 이렇게 해야 ABCDEFG를 찾을 수 있다. 

나누기와 나머지 연산을 사용해서 재생된 시간만큼의 문자열을 만들어 주면 된다.

 

 

 

만들어진 문자열에서 find 함수를 통해서 네오가 기억하는 멜로디를 검색해주면 된다.

 

 

 

하지만 문제에서 말했듯이, ABC#의 경우에는 ABC가 아니다. 간편한 연산을 위해서 C#를 소문자 c의 형태로 변경할 것이다. 이렇게 처리하면, C인지 C#인지 찾지 않아도 한 번만에 처리가 가능하다.

 

 

 


 

 

 

네오가 기억한 멜로디와 악보에 사용되는 음은 C, C#, D, D#, E, F, F#, G, G#, A, A#, B 12개이다.

위의 문장에서, 한 음이라고 한 것에 주목해야 한다. 한 음이라는 것은 1분을 소요하게 된다.

 

 

 

 

문제가 오래걸렸던 이유는, C#의 경우에 C, #을 각각 1음을 체크를 했었다. 문제를 제대로 읽었다면 쉽게 풀 수 있었을 것이다.

 

 

 

 

또한 추가적으로 살펴봐야 할 것은 아래의, 작동이다. 재생시간에 맞춰서 멜로디를 만들기 위해 나누기와 나머지 연산이 아니고, 아래의 형태를 가지게 했는데, 문제가 발생했다. 다음 코드는 종료되지 않는다.

 

 

 

 

#include <iostream>

#include <string>

 

using namespace std;

 

int main(void) {

    string str = "test";

    int val = 5;

    while (true) {

        cout << val - str.size() << endl;

        if (val - str.size() >= 0) {

            val -= str.size();

        }

        else {

            cout << val << endl;

            break;

        }

    }

 

    return 0;

}

 

 

 

이 코드를 실행해보면, val - str.size()의 값이 오버플로우 형태를 가진다. 하지만 if(val - str.size() >= 0) 이후에서 val은 또 정상적인 값을 가진다.

 

 

 

 

원래 알고있는대로라면, 자동 형 변환은 자료형이 큰쪽으로 맞춰져야 한다.

val - (int)str.size()를 사용하면 정상적으로 작동한다. 또한, val -= str.size()의 형태는 자료형이 큰쪽으로 자동 형변환이 이루어진다.

 

 

 

 

반면에, val - str.size()에선 str.size()의 자료형에 맞춰진다. 찾아보니, int(val)와 unsigned int(size())의 rank가 같기 때문에, 무부호형인 unsigned int로 맞춰진다고 한다.

 

 

 

 

val -= str.size()는 val의 int 자료형으로 강제적으로 형변환을 하고 있으니, int형으로 자료형이 맞춰지는게 맞다. 코드를 작성할 때, size()는 자주 사용되기 때문에 참고할만한 사항이다.

 

 

 

 


 

 

 

해설코드(C++).

 

#include <string>

#include <vector>

#include <string.h>

#include <iostream>

 

using namespace std;

 

int strtoTime(string str) {

    int result = 0;

 

    result += 600 * (str[0- '0');

    result += 60 * (str[1- '0');

    result += 10 * (str[3- '0');

    result += 1 * (str[4- '0');

 

    return result;

}

 

string solution(string m, vector<string> musicinfos) {

    string answer = "'(None)'";

    int ans_time = -1;

 

    for (int i = 0; i < musicinfos.size(); i++) {

        char* tok = strtok((char*)musicinfos[i].c_str(), ",");

        int idx = 1;

        int start_time = 0;

        int end_time = 0;

        string song;

        string rem;

        string melody;

 

        while (tok != NULL) {

            if (idx == 1)

                start_time = strtoTime(tok);

            else if (idx == 2)

                end_time = strtoTime(tok);

            else if (idx == 3) {

                song = tok;

                //cout << song << endl;

            }

            else if (idx == 4) {

                rem = tok;

                int time = end_time - start_time;

                while (true) {

                    if (time - (int)rem.length() >= 0) {

                        time -= (int)rem.length();

                        melody.append(rem);

                        if (time == 0)

                            break;

                    }

                    else {

                        if (time < 0)

                            time += (int)rem.length();

                        melody.append(rem.substr(0, time));

                        break;

                    }

                }

 

                //cout << melody << endl;

                size_t found = melody.find(m);

                while (found != string::npos) {

                    if ((int)found + (int)m.length() < (int)melody.length()) {

                        cout << melody[found] << endl;

                        if (melody[(int)found + (int)m.length()] == '#');

                        else {

                            if (answer.compare("'(None)'"== 0) {

                                answer = song;

                                ans_time = end_time - start_time;

                            }

                            else {

                                if (ans_time < end_time - start_time)

                                {

                                    answer = song;

                                    ans_time = end_time - start_time;

                                }

                            }

                            break;

                        }

                    }

 

                    found = melody.find(m, (int)found + 1);

                }

            }

            tok = strtok(NULL",");

            idx++;

        }

    }

    return answer;

}