상세 컨텐츠

본문 제목

[프로그래머스] 방금 그 곡

Algorithm

by 쑤야. 2023. 12. 13. 17:35

본문

로직


  • m에 대해 악보에 포함된 #을 제거준다.
    • 특정 문자열을 포함하는지 여부를 확인해야 하는데, ABC#과 ABC는 모두 ABC를 포함하기 때문이다.
    • C#을 c로 변환하는 등, C와 구분될 수 있도록 변환해준다. 
  • 결과값을 담을 변수를 선언해주는데, 곡의 제목과 재생시간을 같이 담을 수 있는 자료구조를 선택한다. 
  • 시간을 분 단위로 변환하여 재생시간을 구한다.
  • m과 마찬가지로 주어진 악보 정보에 대해 #을 제거준다.
  • 악보 정보를 활용하여 재생 시간만큼의 전체 악보를 생성한다. 문자열 포함 여부를 통해 찾고 있는 곡이 맞는지를 확인한다. 
  • 찾고 있는 곡이 맞다면, 재생시간 비교를 한다. 재생 시간이 더 길다면 result를 갱신해준다. 

 

코드


func solution(_ m:String, _ musicinfos:[String]) -> String {
    
    let m = convert(m)
    
    var result = ("(None)", 0) //곡 제목, 재생 시간
    
    for info in musicinfos {
        let data = info.split(separator: ",").map{ String($0) }
        let playtime = time(data[1]) - time(data[0])
        if isContain(convert(data[3]), playtime) && result.1 < playtime {
            result = (data[2], playtime)
        }
    }
    
    return result.0
    
    func convert(_ string: String) -> String {
        return string
        .replacingOccurrences(of: "C#", with: "c")
        .replacingOccurrences(of: "D#", with: "d")
        .replacingOccurrences(of: "F#", with: "f")
        .replacingOccurrences(of: "G#", with: "g")
        .replacingOccurrences(of: "A#", with: "a")
    }
    
    func time(_ t: String) -> Int {
        let split = t.split(separator: ":").map{ Int($0)! }
        return split[0]*60 + split[1]
    }
    
    func isContain(_ base: String, _ playtime: Int) -> Bool {
        var play = String(repeating: base, count: playtime/base.count+1)
        play = String(play.prefix(playtime))
        return play.contains(m)
    }
}

 

Substring 코드 관련


 

재생 시간만큼의 악보를 구하기 위해서는 아래와 같이 구현할 수 있다. 문제를 풀 때는 1번 방식이 시간 복잡도 측면에서 더 효율적이라고 생각했는데, 사실 최악의 경우엔 차이가 없다. 둘 다 1440개의 원소를 살펴야 한다.. 구현하기 쉬운건 무조건 2번.

 

1. Array 변환 후, 슬라이싱

 

1번 방식의 경우 base인 주어진 악보 정보의 길이가 짧을 경우, 2번보다 더 효율적일 것이다. 슬라이싱을 위해 탐색하는 데이터의 길이가 짧기 때문이다.

 

func isContain(_ base: String, _ playtime: Int) -> Bool {
    var play = String(repeating: base, count: playtime/base.count)
    let baseArray = Array(base).map{ String($0) }
    play += baseArray[0..<playtime%base.count].joined()
    return play.contains(m)
}

2. prefix 메서드 사용

 

base로 주어진 악보 정보의 길이가 길다면, 1번에 비해 비효율적이다. 하지만 최악의 경우를 고려하면 똑같다^^. 

1번 방식보다 훨씬 간편한 2번.

 

func isContain(_ base: String, _ playtime: Int) -> Bool {
    var play = String(repeating: base, count: playtime/base.count+1)
    play = String(play.prefix(playtime))
    return play.contains(m)
}

 

관련글 더보기