주차 요금 계산

Hisop·2022년 11월 18일
0
import Foundation

class node {
    var number:String
    var inTime:String
    var totalTime:Int? = nil
    var next:node? = nil
    var nowIn = false
    
    init (_ number:String, _ inTime:String) {
        self.number = number
        self.inTime = inTime
        self.totalTime = nil
        self.next = nil
        self.nowIn = true
    }
}

var head:node? = nil

func addNode(_ newList:node?) {
    var temp = head
    if head == nil {
        head = newList
    }
    while (temp?.next != nil) {
        temp = temp?.next
    }
    temp?.next = newList
}

func findAdd(_ number:String, _ inTime:String) {
    var temp = head
    while (temp != nil) {
        if number == temp?.number {
            temp?.inTime = inTime
            temp?.nowIn = true
        }
        temp = temp?.next
    }
}

func check_number(_ number:String) -> Bool {
    var temp = head
    while (temp != nil) {
        if number == temp?.number {
            return false 
        }
        temp = temp?.next
    }
    return true
}

func makeMinute(_ inTime:String) -> Int {
    let sp = inTime.split(separator:":")
    return Int(String(sp[0]))! * 60 + Int(String(sp[1]))!
}

func makeTotal (_ number:String, _ outTime:String) {
    var temp = head
    while (temp != nil) {
        if (number == temp?.number) {
            temp?.nowIn = false
            if temp?.totalTime == nil {
                temp?.totalTime = makeMinute(outTime) - makeMinute(temp!.inTime)
            }
            else {
                temp?.totalTime! += makeMinute(outTime) - makeMinute(temp!.inTime)
            }
        }
        temp = temp?.next
    }
}

func nodeSort() -> [Int] {
    var temp = head
    var dict:[String:Int] = [:]
    while temp != nil {
        dict[temp!.number] = temp!.totalTime
        temp = temp?.next
    }
    return dict.sorted { $0.0 < $1.0 }.map { $0.value }
}

func make_result(_ fees:[Int], _ totalTime:[Int]) -> [Int] {
    var result:[Int] = [] 
    for val in totalTime {
        if val <= fees[0] {
            result.append(fees[1])
            continue
        }
        else {
            var temp = val - fees[0]
            temp = temp % fees[2] > 0 ? temp / fees[2] + 1 : temp/fees[2]
            result.append(fees[1] + (temp * fees[3]))
        } 
    }
    return result
}

func solution(_ fees:[Int], _ records:[String]) -> [Int] {
    for st in records {
        let sp = st.split(separator: " ")
        
        if sp[2] == "IN" {
            if head == nil || check_number(String(sp[1])) {
                let lst = node(String(sp[1]), String(sp[0]))
                addNode(lst)
            }
            else {
                findAdd(String(sp[1]), String(sp[0]))
            }
        }
        else if sp[2] == "OUT" {
            makeTotal(String(sp[1]), String(sp[0]))
        }
    }
    var temp = head
    while (temp != nil) {
        if temp!.nowIn == true {
            makeTotal(temp!.number, "23:59")
        }
        temp = temp?.next
    }
    return make_result(fees, nodeSort())
}

문제 링크 - 문제가 긴 편이라 링크로 대체

풀이 자체는 어렵지 않았다.
swift로 연결리스트를 구현하는건 처음이었다.
옵셔널 문법이 어려웠고, 문자열 처리는 여전히 귀찮았다.


주차장에 없는 차량의 출차 / 주차장 안에 있는 차량과 같은 번호의 차량은 진입하지 않는다. 등의 잘못된 입력은 주어지지 않아 예외처리는 생각하지 않아도 되었다.

class node {
  var number:String
  var inTime:String
  var totalTime:Int? = nil
  var next:node? = nil
  var nowIn = false
  
  init (_ number:String, _ inTime:String) {
      self.number = number
      self.inTime = inTime
      self.totalTime = nil
      self.next = nil
      self.nowIn = true
  }
}

한 차량에 대한 하루동안의 총 이용시간을 계산해야했기에 연결리스트가 먼저 떠올랐다. (여러번 입차했을 경우 등)

func solution(_ fees:[Int], _ records:[String]) -> [Int] {
  for st in records {
      let sp = st.split(separator: " ")
      
      if sp[2] == "IN" {
          if head == nil || check_number(String(sp[1])) {
              let lst = node(String(sp[1]), String(sp[0]))
              addNode(lst)
          }
          else {
              findAdd(String(sp[1]), String(sp[0]))
          }
      }
      else if sp[2] == "OUT" {
          makeTotal(String(sp[1]), String(sp[0]))
      }
  }
  var temp = head
  while (temp != nil) {
      if temp!.nowIn == true {
          makeTotal(temp!.number, "23:59")
      }
      temp = temp?.next
  }
  return make_result(fees, nodeSort())
}

일단 반복문을 돌리며 split을 통해 공백기준으로 문자를 분리했다.
sp선언부를 for문으로 올려도 됐을듯?

  for sp in records.split(separator:" ") //느낌으로

이후 In,Out에 따라 분기를 정했다.
In이면서 헤드노드가 비어있거나 중복되는 차량번호(check_number)가 없었다면 새 노드를 생성해주었다.

아니라면 기존 노드를 탐색하여 같은 차량번호에 값을 넣어주었다.

Out일 경우 총 이용시간을 계산하여 node의 totalTime에 넣어주었다.

while을 통해 입차만 하고 출차를 하지 않은 경우(nowIn == true) 23:59분에 출차한것으로 처리해주었다.

이 데이터를 차량번호 순으로 정렬하여 답만 내주면 되었다.

func nodeSort() -> [Int] {
  var temp = head
  var dict:[String:Int] = [:]
  while temp != nil {
      dict[temp!.number] = temp!.totalTime
      temp = temp?.next
  }
  return dict.sorted { $0.0 < $1.0 }.map { $0.value }
}
                                  

어떤식으로 처리할지 고민하다 C++의 map같은 자료형를 사용하고 싶어서 유사한 딕셔너리 타입을 사용했다.
차량 번호를 key로, 총 이용시간을 value로 지정했다.

sorted를 사용하는 부분에서 문법적으로 좀 어려웠다. $0.0에서 .0은 key를 뜻한다. key끼리 비교해서 sort 해줘라 정도로 해석하면 되겠다.
차량번호의 역할은 sort에서 끝이다. map을 활용하여 value만 정리해서 Int형 배열로 리턴해주었다.

func make_result(_ fees:[Int], _ totalTime:[Int]) -> [Int] {
  var result:[Int] = [] 
  for val in totalTime {
      if val <= fees[0] {
          result.append(fees[1])
          continue
      }
      else {
          var temp = val - fees[0]
          temp = temp % fees[2] > 0 ? temp / fees[2] + 1 : temp/fees[2]
          result.append(fees[1] + (temp * fees[3]))
      } 
  }
  return result
}

마지막 계산부분은 문제에서 모두 제시해주었다.
기본요금보다 적게 이용했다면 기본요금만, 아니라면 기본요금 + 단위에 따른 추가금을 올림처리하여 더해주기.


옵셔널 언래핑과정에서 ?와 !를 많이 혼용해서 사용했는데 이 부분은 더 찾아봐야할듯
옵셔널 언래핑
!은 강제 언래핑으로 nil이 아님을 확신할때만 사용하는 문법이고, 실무에선 쓰지 않는것이 원칙이라고...

profile
42seoul - C, C++ / YagomAcademy - Swift

0개의 댓글

Powered by GraphCDN, the GraphQL CDN