Programmers Lv2) 방금그곡
출처: programmers.co.kr/learn/courses/30/lessons/17683#qna
분류: 카카오 블라인드 2018
접근방식
musicinfos를 이용해 정보를 가공하고 주어진 music이 포함되는지 확인하는 문제입니다.
주의할 점은 # 이 포함되어 있는 음을 처리해주는 일인데요,
단순히 "ABC" 가 포함되어 있는지 확인한다면 "ABC#" 인 경우를 걸러주지 못합니다.
이를 체크하기 위해서는 대표적으로 두 가지 방법이 있습니다.
- 토큰화
"ABC#" 를 ["A", "B", "C#"] 와 같이 의미있는 단위로 쪼개서 비교하는 방법입니다. - 치환
이 문제에서 의미있는 음표는 12개 뿐입니다. 따라서 "A#" 과 같은 음을 "a" 와 같이 의미없는 문자로 치환시켜서 해결해줍니다.
저는 토근화를 시키면 배열끼리 비교하는 부분이 까다로울 것 같아서 치환으로 해결했습니다.
해결방법
Parsing
1차적으로 musicinfo를 제가 원하는 정보 형태로 바꾸는 과정이 필요했습니다. 그리고 재생시간만큼 총 재생 된 음악을 만들어줬습니다.
그리고 동시에 포함될 경우 재생시간이 더 긴 것을 선택해야 하기 때문에 재생시간으로 sort 까지 해줬습니다.
let parsedInfos = musicinfos
.map { info -> (Int, String, String) in
let (playTime, title, music) = parseMusic(for: info)
let replacedMusic = replaceSharp(music: music)
let playedMusic = repeatMusic(playTime: playTime, music: replacedMusic)
return (playTime, title, playedMusic)
}
.sorted { $0.0 > $1.0 }
조금 더 구체적으로 살펴보겠습니다.
"," 를 이용해서 쪼개고 재생 시간을 계산했습니다.
재생 시간은 ":"로 쪼개고 분에 60을 곱해서 초 단위로 변경해줬습니다.
func parseMusic(for info: String) -> (Int, String, String) {
let parsed = info.split(separator: ",").map { String($0) }
let playTime = parseToSecond(parsed[1]) - parseToSecond(parsed[0])
return (playTime, parsed[2], parsed[3])
}
func parseToSecond(_ time: String) -> Int {
let parsed = time.split(separator: ":").map { Int($0)! }
return parsed[0] * 60 + parsed[1]
}
재생시간만큼 음악을 반복시켜줬는데요,
재생시간을 음악의 길이로 나눴을 때 몫은 음악의 풀로 반복되어야 하고,
나눈 나머지는 그만큼만 재생되어야 합니다.
func repeatMusic(playTime: Int, music: String) -> String {
var repeatedMusic = ""
let musicTime = music.count
repeatedMusic += String(repeating: music, count: (playTime / musicTime))
repeatedMusic += music.dropLast(musicTime - (playTime % musicTime))
return repeatedMusic
}
치환
말씀드렸다시피 저는 # 음 처리에 치환을 사용했는데요, 더 스마트한 방법이 있을 것 같으나.. 그냥 replacingOccurrences 을 사용해서 일일히 변경해줬습니다 😅
func replaceSharp(music: String) -> String {
var replacedMusic = music
replacedMusic = replacedMusic.replacingOccurrences(of: "C#", with: "c")
replacedMusic = replacedMusic.replacingOccurrences(of: "D#", with: "d")
replacedMusic = replacedMusic.replacingOccurrences(of: "F#", with: "f")
replacedMusic = replacedMusic.replacingOccurrences(of: "G#", with: "g")
replacedMusic = replacedMusic.replacingOccurrences(of: "A#", with: "a")
return replacedMusic
}
나머지는 String이 포함되어 있는지 contains 메소드를 사용했고, 일치하는 음악이 없을 때는
(None) 로 꼭 괄호를 포함해서 써주셔야 합니다!!!
이제 전체 코드를 보시면 이해되실 것 같습니다 :)
import Foundation
func solution(_ m:String, _ musicinfos:[String]) -> String {
let m = replaceSharp(music: m)
let parsedInfos = musicinfos
.map { info -> (Int, String, String) in
let (playTime, title, music) = parseMusic(for: info)
let replacedMusic = replaceSharp(music: music)
let playedMusic = repeatMusic(playTime: playTime, music: replacedMusic)
return (playTime, title, playedMusic)
}
.sorted { $0.0 > $1.0 }
for info in parsedInfos {
let (_, title, playedMusic) = info
if playedMusic.contains(m) {
return title
}
}
return "(None)"
}
func replaceSharp(music: String) -> String {
var replacedMusic = music
replacedMusic = replacedMusic.replacingOccurrences(of: "C#", with: "c")
replacedMusic = replacedMusic.replacingOccurrences(of: "D#", with: "d")
replacedMusic = replacedMusic.replacingOccurrences(of: "F#", with: "f")
replacedMusic = replacedMusic.replacingOccurrences(of: "G#", with: "g")
replacedMusic = replacedMusic.replacingOccurrences(of: "A#", with: "a")
return replacedMusic
}
func parseMusic(for info: String) -> (Int, String, String) {
let parsed = info.split(separator: ",").map { String($0) }
let playTime = parseToSecond(parsed[1]) - parseToSecond(parsed[0])
return (playTime, parsed[2], parsed[3])
}
func parseToSecond(_ time: String) -> Int {
let parsed = time.split(separator: ":").map { Int($0)! }
return parsed[0] * 60 + parsed[1]
}
func repeatMusic(playTime: Int, music: String) -> String {
var repeatedMusic = ""
let musicTime = music.count
repeatedMusic += String(repeating: music, count: (playTime / musicTime))
repeatedMusic += music.dropLast(musicTime - (playTime % musicTime))
return repeatedMusic
}
배운점
# 음을 처리하는 부분에서 막혔었던 문제다.
치환과 토크나이즈.. 메모... ✍️
화이팅!!!