https://school.programmers.co.kr/learn/courses/30/lessons/17683#
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와 같을 때의 값을 처리 안 하면 입력 순서대로 처리하는 조건을 충족할 수 있다.
'Algorithm' 카테고리의 다른 글
[JAVA] n진수를 10진수로, 10진수를 n진수로 (십진수 등 변환하는 법) (0) | 2024.06.26 |
---|---|
[JAVA] 알고리즘 풀 때 HashMap 사용법 정리 (0) | 2023.09.24 |
[JAVA] 프로그래머스 [1차] 뉴스 클러스터링 (0) | 2023.09.06 |
[JAVA] sort 할 때 정렬 기준 만드는 법(feat. Comparator) (0) | 2023.09.02 |
[JAVA] 백준 2470 두 용액 (0) | 2023.07.20 |