programmers.co.kr/learn/courses/30/lessons/17683
안녕하세요 후르륵짭짭 입니다.
저는 이 문제를 보자마자,,, 아 쉽지 않겠다.
라는 생각이 빡! 들었고 역시 쉽지 않았습니다.
그리고 정말 많이 틀렸기 때문에,,,,, 30번 같은 문제를 왜 계속 틀릴지 너무 고생 많이 했습니다.
** 문제 해설 **
func solution(_ m:String, _ musicinfos:[String]) -> String {
var answer : [(time: Int, name : String, index : Int)] = []
//실제로 재생된 음악을 가져오자
var musicList : [(start : String, end : String, name : String, rithym : String)] = []
let newMusicinfos = musicinfos.map { (element) -> [String] in
return element.components(separatedBy: ",")
}
for element in newMusicinfos {
let start = element[0]
let end = element[1]
let name = element[2]
let rithym = element[3]
musicList.append((start, end, name, rithym))
}
//음을 나눠준다.
let temp = Array(m).map { (char) -> String in
return String(char)
}
let rememberMusic = makeMlist(temp)
print(rememberMusic)
// print(musicList)
for element in musicList {
let start = element.start.components(separatedBy: ":")
let end = element.end.components(separatedBy: ":")
let name = element.name
let rithym = element.rithym.map { (char) -> String in
return String(char)
}
//시간 계산
var minute = (Int(end[0])! * 60 + Int(end[1])!) - (Int(start[0])! * 60 + Int(start[1])!)
// print(minute , rithym.count)
var originMusict = makeMlist(rithym)
if(minute < 0) { minute *= -1 } // 23:00 - 00:00
originMusict = makeMusic(minute, originMusict)
// if minute - originMusict.count > 0 {
// originMusict = makeMusic(minute, originMusict)
// }
// else{
// originMusict = makeMusic(minute - originMusict.count, originMusict)
// }
print(originMusict)
var flag = false
for (index, single) in originMusict.enumerated() {
if single == rememberMusic[0] && originMusict.count - index >= rememberMusic.count {
var go = index
for go2 in 0..<rememberMusic.count {
if originMusict[go] != rememberMusic[go2] {
// print("go : \(go) \(originMusict[go]) \(rememberMusic[go2])")
break
}
if go2 == rememberMusic.count - 1{
// print("YES")
answer.append((minute, name, answer.count))
flag = true
}
go += 1
}
}
if flag {
break
}
}
}
answer = answer.sorted(by: { (element1, element2) -> Bool in
return element1.time > element2.time
})
print(answer)
return !answer.isEmpty ? answer.first!.name : "(None)"
}
func makeMusic(_ minute : Int ,_ origin : [String]) -> [String] {
var newRithym : [String] = []
let repeatCnt = minute / origin.count
for _ in 0..<repeatCnt {
newRithym += origin
}
newRithym += origin[0..<(minute % origin.count)]
return newRithym
}
func makeMlist(_ temp : [String]) -> [String] {
var mList : [String] = []
var index = 0
while index < temp.count {
var twoWord = ""
if index < temp.count - 1 {
twoWord = temp[index] + temp[index + 1]
}
else{
twoWord = temp[index]
}
if twoWord == "C#" || twoWord == "D#" || twoWord == "F#" || twoWord == "G#" || twoWord == "A#" {
mList.append(twoWord)
index += 2
}
else{
mList.append(temp[index])
index += 1
}
}
return mList
}
하,,,,, 정말 코드 깁니다 ㅎㅎㅎㅎㅎㅎ
진짜로 깁니다 ㅎㅎㅎㅎ
//실제로 재생된 음악을 가져오자
var musicList : [(start : String, end : String, name : String, rithym : String)] = []
let newMusicinfos = musicinfos.map { (element) -> [String] in
return element.components(separatedBy: ",")
}
for element in newMusicinfos {
let start = element[0]
let end = element[1]
let name = element[2]
let rithym = element[3]
musicList.append((start, end, name, rithym))
}
일단 이렇게 각 문자를 ","를 기준으로 나눠줍니다. 그리고 musicList에 시작 끝 이름 악보를 저장해줍니다.
이제 악보를 바꿔줘야합니다.
다른 사람들 코드를 보면 정말 다양한 방법을 사용했는데, 저는 특별한 기능이 생각 안나서, 직접 바꿔줬습니다.
처음에 두개를 묶고 그 문자가 "C#" || "D#" || "F#" || "G#" || "A#" 이라면 두칸 이동해주고
그게 아니면 한칸만 뒤로 가게 해줘서 문자를 나눠줬습니다.
func makeMlist(_ temp : [String]) -> [String] {
var mList : [String] = []
var index = 0
while index < temp.count {
var twoWord = ""
if index < temp.count - 1 {
twoWord = temp[index] + temp[index + 1]
}
else{
twoWord = temp[index]
}
if twoWord == "C#" || twoWord == "D#" || twoWord == "F#" || twoWord == "G#" || twoWord == "A#" {
mList.append(twoWord)
index += 2
}
else{
mList.append(temp[index])
index += 1
}
}
return mList
}
이렇게 AA#BD#D 라면
AA를 묶고 위의 경우가 아니라면 A만 보내고 다시 A# 보고 위의 경우에 해당하니깐 BD를 보고,, 이렇게 나아갑니다.
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형 일 경우에, replacingOccurrences( A:B)를 사용하면 A를 B로 변경해줍니다.
정확한 알고리즘 원리를 알고 싶은데,, 알 수 있는 경로가 없는 것 같습니다.
이제 시작과 끝 시간을 알아야합니다.
/시간 계산
var minute = (Int(end[0])! * 60 + Int(end[1])!) - (Int(start[0])! * 60 + Int(start[1])!)
var originMusict = makeMlist(rithym)
if(minute < 0) { minute *= -1 } // 23:00 - 00:00
originMusict = makeMusic(minute, originMusict)
이렇게 시간을 구해주는데,,, 문제에 이렇게 되어 있어서 부족하면 건너 뛰는 줄 알았는데, 그게 아니였고
반대로, 한 음악을 중간에 끊을 경우 원본 음악에는 네오가 기억한 멜로디가 들어있다 해도 그 곡이 네오가 들은 곡이 아닐 수도 있다. 그렇기 때문에 네오는 기억한 멜로디를 재생 시간과 제공된 악보를 직접 보면서 비교하려고 한다.
또 이 부분 때문에 너무 많은 시간을 고생 했습니다.
30번을 계속 틀린다면,,, 여기서 잘 못 될 가능성이 높습니다.
if(minute < 0) { minute *= -1 } // 23:00 - 00:00
시간이 23시 부터 00 시가 되면 음수 값이 됩니다. 따라서 양수로 바꿔주는 작업을 해줘야합니다.
저는 이 부분을 수정 해주니 계속 틀리던 30번이 정답 처리 되었습니다.
func makeMusic(_ minute : Int ,_ origin : [String]) -> [String] {
var newRithym : [String] = []
let repeatCnt = minute / origin.count
for _ in 0..<repeatCnt {
newRithym += origin
}
newRithym += origin[0..<(minute % origin.count)]
return newRithym
}
이렇게 분이 주어지면 그 분을 1분 마다 재생되는 음의 개수로 나눠주고 위와 같은 방식으로 해결을 해줍니다.
for (index, single) in originMusict.enumerated() {
if single == rememberMusic[0] && originMusict.count - index >= rememberMusic.count {
var go = index
for go2 in 0..<rememberMusic.count {
if originMusict[go] != rememberMusic[go2] {
// print("go : \(go) \(originMusict[go]) \(rememberMusic[go2])")
break
}
if go2 == rememberMusic.count - 1{
// print("YES")
answer.append((minute, name, answer.count))
flag = true
}
go += 1
}
}
if flag {
break
}
}
그리고 기억하는 음악이 ABCD 이고 재생된 음악이 BBBAB 라고 할때, 같은 A라면 탐색을 시작하게 되고 마지막 까지 동일하면 정답 처리 해줍니다. 그런데 만약 남은 음악이 기억하는 음악 보다 작다면 (AB < ABCD) 탐색을 안해줍니다.
answer = answer.sorted(by: { (element1, element2) -> Bool in
return element1.time > element2.time
})
return !answer.isEmpty ? answer.first!.name : "(None)"
마지막에, 정렬을 해주고 이렇게 첫번째 요소를 반환해주거나 존재하지 않다면 "(None)"을 해주면 정답이 됩니다!
개인적으로 구현하는데,,, 상당히 힘든 문제였습니다.... 따질 조건도 많았고,,, 그래도 어떻게든 해결해서 다행입니다.
다 맞은거 같은데, 틀린게 있다면 꼭 코드 부터 보도록 하겠습니다.
참고 사이트
developer.apple.com/documentation/foundation/nsstring/1412937-replacingoccurrences
'Xcode > Swift - Algorithm' 카테고리의 다른 글
Swift ) 프로그래머스(Lv2) - [3차] 압축 (Hash) (0) | 2020.09.10 |
---|---|
Swift ) 프로그래머스(Lv2) - [1차]프렌즈4블록 (Simulation) (0) | 2020.09.08 |
Swift ) 프로그래머스(Lv2) - 후보키 (DFS&Set) (0) | 2020.09.08 |
Swift ) 프로그래머스(Lv2) - 오픈 채팅방 (Hash) (0) | 2020.09.08 |
Swift ) 프로그래머스(Lv2) - [1차] 캐시 (Hash) (0) | 2020.09.07 |
댓글