algorithm/programmers

[프로그래머스/자바] 방금그곡 풀이 - 2018 KAKAO BLIND RECRUITMENT

hsm914 2022. 12. 29. 23:49
728x90

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

 

프로그래머스

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

programmers.co.kr

 

2018 KAKAO BLIND RECRUITMENT Level 2 문제다.

 

 

Level 2지만 생각보다 오래 걸린 문제다.

접근하기는 쉬운데 테케 몇개 틀리다고 뜨면 반례를 생각해내기가 어려운 것 같다.

 

 

    static String[][] alpha = {{"A#", "a"}, {"G#", "g"}, {"F#", "f"}, {"D#", "d"}, {"C#", "c"}};
    
    // # 들어가는 음을 다른 알파벳으로 치환
    static String replaceMusic(String m) {
    	String ret = m;
    	for(String[] a : alpha)
            ret = ret.replaceAll(a[0], a[1]);
    	
        return ret;
    }

세 번째 입출력 예시에서 ABC와 ABC#를 구분해야 하는 것처럼 #이 포함된 음을 적절히 처리해 주어야 한다.

처음엔 음을 문자열 배열형태로 구성해서 ABC#를 {"A", "B", "C#"}로 만들려고 했다.

이렇게 해도 풀 수는 있지만 더 복잡해질 것 같아 #이 들어있는 음을 소문자로 치환했다.

 

네오가 기억하는 멜로디, musicinfos에 주어진 곡의 음 모두 위와 같이 치환해야 한다.

먼저 네오가 기억하는 멜로디를 치환한다.

 

 

musicinfos에 있는 원소들 하나하나씩 꺼내서 곡의 음을 치환한다.

그리고 시작 시간, 끝 시간, 곡의 음을 통해 실제 재생된 음을 구하고 제목도 구한다.

    static String[] getMusic(String str) {
    	StringTokenizer st = new StringTokenizer(str, ",");
        int start = strToInt(st.nextToken()); // 시작 시간
        int end = strToInt(st.nextToken()); // 끝 시간
        int time = end - start;
        /*
        생략 
        */
    }
    
    // HH:MM 형태의 시간을 분으로 변환
    static int strToInt(String str) {
        StringTokenizer st = new StringTokenizer(str, ":");
        return Integer.parseInt(st.nextToken()) * 60 + Integer.parseInt(st.nextToken());
    }

시작 시간과 끝 시간을 통해 곡의 재생 시간을 구하는 방법은 위와 같다.

먼저 구분자가 ","인 StringTokenizer를 통해 문자열 형태의 시작 시간, 끝 시간을 int형태의 분으로 치환한다.

끝 시간에서 시작 시간을 빼면 곡의 재생 시간이 된다.

 

 

        String title = st.nextToken();

제목도 동일한 StringTokenizer를 통해 구한다.

 

 

        String music = replaceMusic(st.nextToken()); // 곡의 음

        int len = music.length();
        String[] ret = new String[2];
        ret[0] = title;
        ret[1] = music.repeat(time / len) + music.substring(0, time % len);
        // 재생 시간을 곡 길이로 나눈 몫 만큼 반복, 반복 후 남은 시간이 있다면 붙이기

실제 재생된 음을 구하기 위해서는 위와 같은 방법을 사용한다.

실제 곡의 음보다 재생된 시간이 짧은 경우, 재생된 시간만큼 곡이 재생된다. (곡의 시작부터 재생 시간까지)

실제 곡의 음보다 재생된 시간이 긴 경우, 실제 곡을 재생된 시간만큼 반복한다.

예를 들어 실제 곡이 7이고 재생된 시간이 18일 경우,

실제 곡 7을 2번(18/7) 반복(14)하고, 그 뒤에 나머지 4(18%7)를 이어붙여주면 된다.

 

즉, 문자열의 repeat과 substring을 통해 재생된 음을 구성할 수 있다.

 

 

    static void isSameMusic(String target, String title, String music) {
        int len = music.length();
    	if(music.contains(target) && ansTime < len) {
            ans = title;
            ansTime = len;
        }
    }

네오가 기억하는 멜로디와 노래의 제목, 노래의 재생된 음을 통해

조건에 만족하는 노래인지 판단한다.

contains을 통해 네오가 기억하는 멜로디가 포함되어 있다면 조건에 만족하는 노래다.

  • 조건이 일치하는 음악이 여러 개일 때에는 라디오에서 재생된 시간이 제일 긴 음악 제목을 반환한다. 재생된 시간도 같을 경우 먼저 입력된 음악 제목을 반환한다.

라는 조건을 만족하기 위해 if문에 ansTime < len도 추가한다.

즉, 현재 저장되어 있는 ans의 재생시간보다 더 긴 경우에만 ans를 갱신한다.

이를 구현하기 위해 ans의 재생시간인 ansTime의 초깃값을 0으로 두어야 한다. 

 

  • 조건이 일치하는 음악이 없을 때에는 “(None)”을 반환한다.

또한 위 조건을 만족하기 위해 ans의 초깃값은 "(None)"으로 둔다.

 

 

 

배운점 및 느낀점

처음엔 조건이 만족하는 음악인지 찾고자 할 때 for문으로 일일이 다 비교했었다.

시간 복잡도는 그렇게 차이나지 않았지만 뭔가를 잘못 생각했는지 테케 21번이 계속 틀려서 시간을 좀 오래 잡아먹었다.

그리고 contains 메소드를 활용하면 더 간단할 것 같아서 바꾸니까 테케 21번도 정답 처리 되었다.

 

또한 조건이 일치하는 음악이 여러 개일 때는 재생된 시간이 가장 긴 음악 제목을 반환한다는 조건이 중요하다.

처음엔 제목이 가장 긴 음악 제목이라고 잘못 이해해서, 6, 21, 30 등등.. 여러 테케를 틀렸었다.

제목이 아닌 "재생 시간"이 가장 긴 제목을 반환해야 한다!

 

 

 

전체 코드

import java.util.*;

class Solution {
    static String[][] alpha = {{"A#", "a"}, {"G#", "g"}, {"F#", "f"}, {"D#", "d"}, {"C#", "c"}};
    static String ans = "(None)";
    static int ansTime = 0;
	
    public String solution(String m, String[] musicinfos) {
    	String target = replaceMusic(m);
    	
    	for(int i=0;i<musicinfos.length;i++) {
            String[] music = getMusic(musicinfos[i]);
            isSameMusic(target, music[0], music[1]); // 네오가 기억한 멜로디, 제목, 재생된 음
        }
    	
        return ans;
    }
    
    static String[] getMusic(String str) {
    	StringTokenizer st = new StringTokenizer(str, ",");
        int start = strToInt(st.nextToken()); // 시작 시간
        int end = strToInt(st.nextToken()); // 끝 시간
        int time = end - start;
        
        String title = st.nextToken(); 
        String music = replaceMusic(st.nextToken()); // 곡의 음

        int len = music.length();
        String[] ret = new String[2];
        ret[0] = title;
        ret[1] = music.repeat(time / len) + music.substring(0, time % len);
        // 재생 시간을 곡 길이로 나눈 몫 만큼 반복, 반복 후 남은 시간이 있다면 붙이기
        
        return ret;
    }
    
    // HH:MM 형태의 시간을 분으로 변환
    static int strToInt(String str) {
        StringTokenizer st = new StringTokenizer(str, ":");
        return Integer.parseInt(st.nextToken()) * 60 + Integer.parseInt(st.nextToken());
    }
    
    // # 들어가는 음을 다른 알파벳으로 치환
    static String replaceMusic(String m) {
    	String ret = m;
    	for(String[] a : alpha)
            ret = ret.replaceAll(a[0], a[1]);
    	
        return ret;
    }
    
    static void isSameMusic(String target, String title, String music) {
        int len = music.length();
    	if(music.contains(target) && ansTime < len) {
            ans = title;
            ansTime = len;
        }
    }
    
}
728x90