오늘도 카카오 삽질대장정..☆ #
에 따른 음 처리와 인덱스가 꼬이는 바람에 시간이 오래 걸렸다.
이 문제를 풀면서 느낀 건, 메소드는 간단하면 간단할 수록, 명료하면 명료할 수록 좋다는 점이다. 메소드 하나에 구구절절 끼워넣으니 디버깅하다가 머리 터질 뻔했는데, 최대한 분리하고 한 메소드에서 하나의 일만 하도록 하니까 정리가 되면서 문제가 풀렸다. 앞으로도 조건들을 하나의 문장이나 메소드에 끼워 넣지 말고 차근차근 나눠가며 풀면 더 빨리 그리고 정확하게 풀 수 있을 것 같다.
그리고 조건들을 확인하는 순서도 중요한 것 같다. if문 여러 개가 중첩으로 쌓이면 당연히 놓치는 조건이 발생하고 통과하지 않는 테스트 케이스가 생겨버린다. 분기문을 최소한으로 나누고 순서를 잘 고려하도록 항상 여러번 점검해야겠다.
parseMusicInfos()
: 주어진 musicInfos
를 파싱해서 Music
리스트에 저장한다.
split()
메소드를 사용했다. 음악 제목에 쉼표(,)가 없다는 조건이 있었기에 사용할 수 있었다.playNotes
, originalNotes
는 Music
생성자에서 파싱하도록 했다.findTargetMusic()
: 주어진 m
을 포함하고 있는 음악을 musics
를 차례로 탐색하며 찾는다.
a. startIndex
와 endIndex
를 가지고 음악의 부분음인 subNotes
를 구하고, targetNotes
와 비교한다.
calcNoteLength()
에서 구한다. 그냥 String length()
로 하면 #
처리때문에 답이 맞지 않는다.b. 일치하는 음악이 여러 개인 경우 isUpdatable()
에서 조건을 체크해서 가장 최적인 음악으로 갱신한다.
찾아진 것이 없으면 (None)
을, 있으면 음악 제목을 리턴한다.
import java.util.*;
class Solution {
private List<Music> musics = new ArrayList<>();
public String solution(String m, String[] musicInfos) {
parseMusicInfos(musicInfos);
Music result = findTargetMusic(m);
if (result == null) return "(None)";
return result.title;
}
private void parseMusicInfos(String[] musicInfos) {
for (String musicInfo : musicInfos) {
String[] chunks = musicInfo.split(",");
musics.add(new Music(chunks[0], chunks[1], chunks[2], chunks[3]));
}
}
private Music findTargetMusic(String targetNotes) {
Music result = null;
for (Music music : musics)
if (isTargetAndMusicMatch(targetNotes, music))
if (result == null || isUpdatable(result, music))
result = music;
return result;
}
private boolean isTargetAndMusicMatch(String targetNotes, Music music) {
int startIndex = 0, endIndex = calcNoteLength(targetNotes) - 1;
while (endIndex < music.playedDuration) {
String subNotes = music.getSubNotes(startIndex, endIndex);
if (targetNotes.equals(subNotes)) return true;
startIndex++;
endIndex++;
}
return false;
}
private int calcNoteLength(String notes) {
int count = 0;
for (int i = 0; i < notes.length(); i++) {
count++;
if (i + 1 < notes.length() && notes.charAt(i + 1) == '#') i++;
}
return count;
}
private boolean isUpdatable(Music result, Music music) {
if (music.playedDuration > result.playedDuration) return true;
return musics.indexOf(music) < musics.indexOf(result);
}
}
class Music {
int startTime;
int endTime;
int playedDuration;
String title;
List<String> originalNotes;
List<String> playedNotes;
public Music(String startTime, String endTime, String title, String notes) {
this.startTime = parseTime(startTime);
this.endTime = parseTime(endTime);
playedDuration = this.endTime - this.startTime;
this.title = title;
this.originalNotes = parseOriginalNotes(notes);
this.playedNotes = getPlayedNotes();
}
private int parseTime(String timeStr) {
String[] time = timeStr.split(":");
int hour = Integer.parseInt(time[0]);
int minute = Integer.parseInt(time[1]);
return hour * 60 + minute;
}
private List<String> parseOriginalNotes(String notes) {
List<String> result = new ArrayList<>();
String note;
for (int i = 0; i < notes.length(); i++) {
note = notes.charAt(i) + "";
if (i + 1 < notes.length() && notes.charAt(i + 1) == '#') {
note += "#";
i++;
}
result.add(note);
}
return result;
}
private List<String> getPlayedNotes() {
List<String> result = new ArrayList<>();
if (this.playedDuration > this.originalNotes.size()) {
for (int i = 0; i < this.playedDuration / this.originalNotes.size(); i++)
result.addAll(originalNotes);
for (int i = 0; i < this.playedDuration % this.originalNotes.size(); i++)
result.add(this.originalNotes.get(i));
} else {
for (int i = 0; i < this.playedDuration; i++)
result.add(this.originalNotes.get(i));
}
return result;
}
public String getSubNotes(int startIndex, int endIndex) {
StringBuilder sb = new StringBuilder();
for (int i = startIndex; i <= endIndex; i++)
sb.append(this.playedNotes.get(i));
return sb.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Music)) return false;
Music music = (Music) o;
return Objects.equals(title, music.title);
}
@Override
public int hashCode() {
return Objects.hash(title);
}
}