Algorithm / 주차 요금 계산

알고리즘 코드카타

목록 보기
48/59

문제

프로그래머스 / 주차 요금 계산

1) 문제 풀이

func solution(_ fees:[Int], _ records:[String]) -> [Int] {
    let baseTime = fees[0]
    let baseCost = fees[1]
    let unitTime = fees[2]
    let unitCost = fees[3]
    
    var dic: [String:[Int]] = [:]
    var answer: [Int] = []
    
    for car in records {
        let record = car.split(separator: " ").map { String($0) }
        let minute = record[0].split(separator: ":").compactMap { Int($0) }
        let time = minute.reduce(0) { ($0 * 60) + $1 }
        
        dic[record[1], default: []].append(time)
    }
    
    for record in dic.sorted(by: { $0.key < $1.key }) {
        var values = record.value
        var currentTime = 0
        var times: Int = 0
                
        if values.count % 2 == 0 {
            for (i, time) in values.enumerated() {
                if (i + 1) % 2 == 0 {
                    times += (time - currentTime)
                    currentTime = 0
                } else {
                    currentTime = time
                }
            }
        } else {
            let outCost = 1439 - values.removeLast()
            
            for (i, time) in values.enumerated() {
                if (i + 1) % 2 == 0 {
                    times += (time - currentTime)
                    currentTime = 0
                } else {
                    currentTime = time
                }
            }
            
            times += outCost
        }
                
        if times <= baseTime {
            answer.append(baseCost)
        } else {
            var excess = Int(Double((times - baseTime) / unitTime))
            
            if ((times - baseTime) % unitTime) != 0 {
                excess += 1
            }
            
            let cost = baseCost + Int(excess * unitCost)
            answer.append(cost)
        }
    }
    
    return answer
}

결과

2) 코드 개선

✅ 코드 문제점 및 개선 포인트

  • 시간 계산 코드 중복

    for (i, time) in values.enumerated() {
      if (i + 1) % 2 == 0 {
          times += (time - currentTime)
          currentTime = 0
      } else {
          currentTime = time
      }
    }

    이 로직은 values.count % 2 == 0else 둘 다에 들어가 있는데, 중복된 코드이기 때문에 개선이 가능하다.
    조건 분기 없이 한 번만 순회하면서 IN과 OUT 페어를 처리하고, 짝이 안 맞는 경우 마지막에 23:59를 직접 계산하는 방식이 더 깔끔하다.

  • 올림 계산 방식 복잡

    var excess = Int(Double((times - baseTime) / unitTime))
    
    if ((times - baseTime) % unitTime) != 0 {
      excess += 1
    }

    이 부분은 Swift의 ceil을 사용하거나, 정수 연산으로도 올림을 간단하게 구현할 수 있다.

    let over = max(0, times - baseTime)
    let cost = baseCost + ((over + unitTime - 1) / unitTime) * unitCost
  • 출차되지 않은 차량 처리 방식
    출차 안 된 차량 처리 로직도 조건 분기 없이 처리할 수 있을 것이다.
    모든 차량의 시간을 짝지어 순회하면서, 마지막에 남은 IN이 있으면 23:59로 간주해 처리하면 된다.

개선된 코드

func solution(_ fees: [Int], _ records: [String]) -> [Int] {
    let baseTime = fees[0]
    let baseCost = fees[1]
    let unitTime = fees[2]
    let unitCost = fees[3]

    var carRecords: [String: [Int]] = [:]

    // 1. 기록을 정리 (입차 시간 저장)
    for record in records {
        let parts = record.split(separator: " ").map { String($0) }
        let timeParts = parts[0].split(separator: ":").compactMap { Int($0) }
        let totalMinutes = timeParts[0] * 60 + timeParts[1]
        let carNumber = parts[1]
        
        carRecords[carNumber, default: []].append(totalMinutes)
    }

    var result: [(String, Int)] = []

    for (carNumber, times) in carRecords {
        var totalTime = 0
        var stack = times

        // 2. IN/OUT 짝 계산
        while !stack.isEmpty {
            let inTime = stack.removeFirst()
            let outTime = stack.isEmpty ? 1439 : stack.removeFirst()
            totalTime += outTime - inTime
        }

        // 3. 요금 계산
        let over = max(0, totalTime - baseTime)
        let fee = baseCost + ((over + unitTime - 1) / unitTime) * unitCost
        result.append((carNumber, fee))
    }

    // 4. 차량 번호 오름차순 정렬 후 요금만 리턴
    return result.sorted { $0.0 < $1.0 }.map { $0.1 }
}

결과

profile
이유있는 코드를 쓰자!!

0개의 댓글