프로그래머스 - [3차] 방금그곡
코드
import java.time.Duration;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
class Solution {
String[] musicinfos;
Map<String, String> musicStartTime = new HashMap<>();
public String solution(String m, String[] musicinfos) {
this.musicinfos = musicinfos;
String answer = null;
Map<String, List<String>> playedMelody = playMusicResult(m);
if (playedMelody.isEmpty()) {
return "(None)";
}
if (playedMelody.size() == 1) {
return playedMelody.keySet().stream().collect(Collectors.toList()).get(0);
}
answer = choiceBestMelody(playedMelody);
return answer;
}
private String choiceBestMelody(Map<String, List<String>> playedMelody) {
List<String> result = new ArrayList<>();
List<String> keySet = playedMelody.keySet()
.stream()
.sorted((o1, o2) -> playedMelody.get(o2).size() - playedMelody.get(o1).size())
.collect(Collectors.toList());
int longestMin = playedMelody.get(keySet.get(0)).size();
for (String key : keySet) {
List<String> s = playedMelody.get(key);
if (s.size() != longestMin) {
break;
}
result.add(key);
}
if (result.size() == 1) {
return result.get(0);
}
return result.stream()
.sorted(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
o1 = musicStartTime.get(o1);
o2 = musicStartTime.get(o2);
String[] splitO1 = o1.split(":");
String[] splitO2 = o2.split(":");
if (Integer.parseInt(splitO1[0]) - Integer.parseInt(splitO2[0]) == 0) {
return Integer.parseInt(splitO1[1]) - Integer.parseInt(splitO2[1]);
}
return Integer.parseInt(splitO1[0]) - Integer.parseInt(splitO2[0]);
}
})
.collect(Collectors.toList())
.get(0);
}
public Map<String, List<String>> playMusicResult(String targetMelody) {
Map<String, List<String>> result = new HashMap<>();
for (String musicinfo : musicinfos) {
String[] musicinfoArr = musicinfo.split(",");
String startTime = musicinfoArr[0];
String endTime = musicinfoArr[1];
String songName = musicinfoArr[2];
String musicalNote = musicinfoArr[3];
Duration between = Duration.between(LocalTime.parse(startTime), LocalTime.parse(endTime));
long minDiff = between.toMinutes();
List<String> play = new ArrayList<>();
List<String> musicalNoteArr = noteToStringList(musicalNote);
int idx = 0;
int z = 1;
while (minDiff > 0) {
if (idx == musicalNoteArr.size()) {
idx = 0;
} else {
play.add(musicalNoteArr.get(idx++));
minDiff--;
}
}
List<String> transTargetMelody = noteToStringList(targetMelody);
if (play.size() >= transTargetMelody.size()) {
if (Collections.indexOfSubList(play, transTargetMelody) != -1) {
result.put(songName, play);
musicStartTime.put(songName, startTime);
}
}
}
return result;
}
private List<String> noteToStringList(String musicalNote) {
char[] chars = musicalNote.toCharArray();
List<String> result = new ArrayList<>();
for (int i = 0; i < chars.length; i++) {
if (chars[i] == 'C' || chars[i] == 'D' || chars[i] == 'F' || chars[i] == 'G' || chars[i] == 'A') {
if (i + 1 < chars.length && chars[i + 1] == '#') {
result.add(String.valueOf(chars[i]) + chars[i + 1]);
i++;
continue;
}
}
result.add(String.valueOf(chars[i]));
}
return result;
}
}
- #이 붙은 악보 처리에 시간이 훌쩍 가버렸는데, 다른사람 풀이보니 악보에 포함되지 않은 다른 문자열로 바꿔버리더라..하하 레벨1할때 그런 방법으로 했던 것 같은데 깜빡했다.
- 그래도 바꾸지 않고 명확하게 #이 붙은 방법으로 해결했다.
- 각 동작들을 메서드화 하니 String에서
List<String> 등 반환타입을 변경하더라도 수정할 부분이 적어 좋았다.
- String으로 네오가 기억하는 멜로디가 있는지 파악할 때 #때문에 리스트로 바꿔서 명확하게 했지만, 리스트가 연속으로 있어야 함을 어떻게 보장하고 확인하지.. 고민하다가 뤼튼에게 Help..!
- 나처럼 푼 사람이 있을까.. 3시간 걸린듯 하하
배열, 리스트 연속적으로 포함되었는지 확인하기
- 배열 : Apache Commons Lang 라이브러리의 ArrayUtils 클래스는 indexOf 메서드이용
- 첫 번째 인자로 받은 배열에서 두 번째 인자로 받은 부분 배열이 처음으로 나타나는 위치의 인덱스를 반환
- 없으면 -1 반환
import org.apache.commons.lang3.ArrayUtils;
public class Main {
public static void main(String[] args) {
int[] array = {1, 2, 3, 4, 5, 6};
int[] subArray = {3, 4, 5};
int index = ArrayUtils.indexOf(array, subArray);
System.out.println(index);
}
}
- 리스트 : Collections.indexOfSubList 활용
- 첫 번째 인자로 받은 리스트에서 두 번째 인자로 받은 리스트가 처음으로 나타나는 위치의 인덱스를 반환
- 없으면 -1 반환
List<Integer> source = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> target = Arrays.asList(3, 4, 5);
int index = Collections.indexOfSubList(source, target);
System.out.println(index);