codingtest

방금그곡

2026-07-29
2분 분량
JAVA프로그래머스

문제 링크

문제 요약

  • 기억한 멜로디 m과 방송된 곡들의 정보(musicinfos)가 주어진다
  • 각 곡은 시작·종료 시각만큼 처음부터 반복 재생된 것으로 간주한다
  • 재생된 악보 안에 m이 그대로 들어있는 곡 중, 재생 시간이 가장 긴 곡의 제목을 찾는다
  • 일치하는 곡이 없으면 "(None)"을 반환한다

문제 풀이

처음에는 악보 문자열을 그대로 이어붙이고 indexOf로 비교하면 될 줄 알았다.

하지만 이 방식은 #이 붙은 음에서 문제가 생긴다.

#이 붙은 음은 두 글자(C#처럼)로 표현되는데, 문자열을 그대로 두고 검색하면 C# 안에 있는 C까지 C로 잘못 걸릴 수 있다.

실제로 세 번째 예시에서 HELLO의 악보는 C#DEFGABC#DEFGAB인데, 여기서 기억한 멜로디 ABC를 그대로 찾으면 C# 뒤에 이어지는 DEFGAB와 우연히 겹쳐 잘못된 매칭이 생길 수 있다.

이 문제의 핵심은 샵이 붙은 음을 소문자 알파벳 하나로 치환해서 모든 음을 한 글자로 통일하는 것이다.

이렇게 바꾸면 음 하나가 항상 한 글자에 대응하므로 순수한 문자열 검색으로 안전하게 비교할 수 있다.

  • convert에서 다음 글자가 #이면 현재 음을 소문자로 바꾸고 한 글자를 건너뛴다
  • 각 곡은 재생 시간만큼 악보를 반복해서 이어붙인 뒤, 그 안에 변환된 m이 포함되는지 확인한다
  • 조건을 만족하는 곡 중 재생 시간이 가장 긴 곡을 갱신해 나간다

최종 코드

java
import java.util.*;

class Solution {
    public int toMin(String time){
        int h = Integer.parseInt(time.substring(0,2));
        int m = Integer.parseInt(time.substring(3));
        
        return h*60+m;
    }
    
    public String convert(String code) {
        StringBuilder result = new StringBuilder();
        
        for (int i = 0; i < code.length(); i++) {
            char now = code.charAt(i);
            
            // 다음 글자가 #이면 현재 음을 소문자 한 글자로 합쳐서 처리
            if (i + 1 < code.length() && code.charAt(i + 1) == '#') {
                result.append(Character.toLowerCase(now));
                i++;
            } else {
                result.append(now);
            }
        }
        
        return result.toString();
    }
    
    public String solution(String m, String[] musicinfos) {
        int max = -1;
        String answer = "(None)";
        m = convert(m);
        
        for(int i=0;i<musicinfos.length;i++){
            StringTokenizer st = new StringTokenizer(musicinfos[i], ",");
            
            int start = toMin(st.nextToken());
            int end = toMin(st.nextToken());
            String name = st.nextToken();
            String c = convert(st.nextToken());
            
            int time = end - start;
            StringBuilder code = new StringBuilder();
            
            // 재생 시간만큼 악보를 처음부터 반복해서 이어붙인다
            for(int j=0;j<time;j++){
                code.append(c.charAt(j%c.length()));
            }
            
            if(code.indexOf(m) != -1 && time > max){
                max = time;
                answer = name;
            }
            
        }
        return answer;
    }
}

함께 읽으면 좋은 글

코딩 테스트2026-08-23

택배상자

order 배열은 택배 기사님이 원하는 상자 적재 순서다 기존 컨테이너 벨트는 1번부터 순서대로만 꺼낼 수 있다 보조 벨트는 스택처럼 마지막에 넣은 것부터 꺼낼 수 있다 원하는 순서대로 최대한 실을 수 있는 상자 개수를 구하는 문제다 처음에는 기존 벨트를 실제 리스트로 만들어…

코딩 테스트2026-08-23

롤케이크 자르기

topping 배열은 롤케이크에 일렬로 올라간 토핑 번호다 한 지점을 잘라 두 조각으로 나눴을 때, 양쪽 토핑 종류 수가 같아야 공평하게 나눈 것이다 공평하게 자를 수 있는 방법의 수를 구하는 문제다 처음에는 자르는 위치마다 왼쪽과 오른쪽 배열을 나눠서 각각 서로 다른 토핑…

코딩 테스트2026-08-23

할인 행사

want, number 배열로 정현이가 원하는 제품과 수량을 표현한다 discount 배열은 XYZ 마트가 매일 할인하는 제품 목록이다 연속된 10일 동안 할인 제품 종류와 수량이 want, number와 정확히 일치해야 회원가입할 수 있다 그런 시작일이 총 몇 번 있는지…

코딩 테스트2026-08-23

숫자 변환하기

자연수 x를 y로 바꾸는 데 x+n, x2, x3 세 가지 연산을 쓸 수 있다 x를 y로 바꾸는 최소 연산 횟수를 구하는 문제다 만들 수 없으면 -1을 반환한다 처음에는 x에서 시작해서 세 가지 연산을 재귀적으로 다 시도해보고 y에 도달하는 경로 중 가장 짧은 걸 고르면…