/* constants */
const REG_EXP = /(C|D|F|G|A)#/g;
const NONE = "(None)"
/* HH:MM 형식의 시간을 분 단위로 변환 */
const getMinutesTime = (time) => {
const [hour, minute] = time.split(':');
return (Number(hour) * 60) + Number(minute);
}
/* 음악 재생 시간 반환 */
const getPlayTime = (start, end) => {
const startTime = getMinutesTime(start);
const endTime = getMinutesTime(end);
return endTime - startTime;
}
/* 실제 재생된 음악 정보 반환 */
const getPlayMusic = (musicNotes, playTime) => {
let playMusic = musicNotes;
const musicLength = playMusic.length;
const repeatCount = Math.ceil(playTime / musicLength);
// 음악 정보의 길이가 음악 재생 시간보다 적을 경우
if (musicLength < playTime) {
// 음악 정보를 repeatCount 만큼 반복
playMusic = musicNotes.repeat(repeatCount);
}
// 실제 음악이 재생된 시간만큼 음악 정보 길이를 잘라서 반환
return playMusic.slice(0, playTime + repeatCount);
}
/* 악보에 사용되는 음 중 # 기호가 포함된 음일 경우, 영소문자로 변환 */
const getReplaceMusicNotes = (musicNotes) => {
return musicNotes.replace(REG_EXP, (_, match) => match.toLowerCase());
}
function solution(m, musicinfos) {
const answer = new Map();
const neoMusicNotes = getReplaceMusicNotes(m);
musicinfos.forEach((musicInfo) => {
const [startTime, endTime, title, music] = musicInfo.split(',');
const musicNote = getReplaceMusicNotes(music);
const playTime = getPlayTime(startTime, endTime);
const playMusic = getPlayMusic(musicNote, playTime);
if (playMusic.includes(neoMusicNotes)) {
answer.set(title, playTime);
}
})
const sortedAnswer = [...answer].sort((a, b) => {
const aPlayTime = a[1];
const bPlayTime = b[1];
if(aPlayTime > bPlayTime) return -1;
if(aPlayTime < bPlayTime) return 1;
return 0;
});
// 조건이 일치하는 음악이 없는 경우 "(None)"을 반환
// 조건이 일치하는 음악이 있는 경우 sortedAnswer의 첫 번째 요소의 title을 반환
return answer.size === 0 ? NONE : sortedAnswer[0][0];
}
처음 생각했던 풀이에서는 악보 내 #
기호의 갯수를 포함하여 재생된 음악의 악보를 구했습니다. 이 후 네오가 기억하는 멜로디가 재생된 음악의 악보에 includes
를 이용하여 포함 여부를 확인하여 답을 구하는 과정을 구상했습니다.
이 때 문제점은 악보가 ABC#DEF
이고 네오가 기억하는 멜로디가 ABC
일 경우, true
를 반환한다는 점입니다.
따라서, #
기호가 포함된 음의 경우 다른 글자로 변환(위 풀이에서 영소문자로 변환)하여 구분될 수 있도록 했습니다.
#
기호가 포함된 음을 영소문자로 변환하는 과정에서 replace
를 사용했는데 다른 분의 풀이를 통해 replace
를 다음과 같이 사용할 수 있다는 것을 알게 되었습니다.
String.prototype.replace()
replace
메서드는 문자열의 패턴이 일치한다면 새로운 문자열로 반환할 수 있도록 합니다.
// Syntax
replace(pattern, replacement)
pattern
replacement
replacement
에 대체 함수 지정// Syntax
function replacer(match, p1, p2, /* …, */ pN, offset, string, groups) {
return replacement;
}
match
p1, p2, ..., pn
p1
, 두 번째 그룹은 p2
, ... 순차적으로 pn
에 매칭된 값을 전달받습니다.offset
input
replacer
함수가 호출된 전체 문자열을 나타냅니다.// replacement에 대체 함수 지정 예시
const str = 'Hello John Doe, Hello Jane Doe';
function replacer(match, p1, offset, input) {
console.log('Matched:', match);
console.log('Group 1:', p1);
console.log('Start offset:', offset);
console.log('Input string:', input);
// 치환된 문자열을 반환
return 'REPLACED';
}
const newStr = str.replace(/Hello (John|Jane) Doe/g, replacer);
console.log('Result:', newStr);
// 출력 결과
> Matched: Hello John Doe
> Group 1: John
> Start offset: 0
> Input string: Hello John Doe, Hello Jane Doe
> Matched: Hello Jane Doe
> Group 1: Jane
> Start offset: 16
> Input string: Hello John Doe, Hello Jane Doe
> Result: REPLACED, REPLACED
const REG_EXP = /(C|D|F|G|A)#/g
/* 악보에 사용되는 음 중 # 기호가 포함된 음일 경우, 영소문자로 변환 */
const getReplaceMusicNotes = (musicNotes) => {
return musicNotes.replace(REG_EXP, (_, match) => match.toLowerCase());
}
const mucicNotes = "CC#BCC#BCC#BCC#B";
console.log(getReplaceMusicNotes(mucicNotes)); // CcBCcBCcBCcB
참고