티스토리 뷰

코드카타

 

주차 요금 계산

 

문제

 

이 문제 풀려면 stack, Pair, Map, List, split()의 개념을 알아야한다.

(여기서 맵과 리스트는 가변형으로 선언된다.)

 

배열 다루는 실력 늘리는 문제라고 할 수 있다.

 

 

입출력 예시

 

차량 수 만큼 주차요금을 계산한다.

 

 

풀이

import kotlin.math.ceil

class Solution {
    fun solution(fees: IntArray, records: Array<String>): List<Int> {
        val stack = mutableListOf<Pair<Int, Int>>() // 입차 후 출차기록이 없는 차 리스트
        val ptSumMap = mutableMapOf<Int, Int>() // 차량별로 누적 주차 시간을 저장할 맵
		
        // 주어진 입/출차 기록을 처리
        for (record in records) {
            // 기록을 시간, 차량번호, 입/출차 여부로 분리
            val (t, n, io) = record.split(" ")
            val num = n.toInt()
			
            // 시간을 분으로 변환
            val time = t.split(":").map { it.toInt() }
            val m = time[0] * 60 + time[1]

            val p = num to m // 차량번호와 입출차 시각을 Pair로 묶어서 입차 기록 생성
            
            if (io == "IN") { // 현재 내역이 "입차"에 해당한다면
            
                stack.add(p) // 입차 기록을 스택에 추가
                
            } else { // 현재 내역이 "출차"에 해당한다면
            
                // 현재 차량의 최근 입차 기록 찾기
                val record = stack.find { it.first == p.first } 
                
                // 입차 기록이 존재한다면
                if (record != null) {
                     // 현재 차량의 주차시간 계산
                    val pt = p.second - record.second
                    // 누적 주차 시간 업데이트
                    ptSumMap[p.first] = ptSumMap.getOrDefault(p.first, 0) + pt 
                    // 스택에서 현재 차량의 입차 기록 제거
                    stack.remove(record)
                }
            }
        }
		
        // 입차기록만 존재하는 차가 있다면
        for (i in stack) {
            // 그 차의 주차요금 계산
            ptSumMap[i.first] = ptSumMap.getOrDefault(i.first, 0) + 1439 - i.second
        }
		
        val (bt, bm, ut, um) = fees // 주차 요금 정산을 위한 변수 선언
        var res = mutableListOf<Int>() // 주차 요금 리스트
        
        // 맵을 차량 번호 순으로 정렬 후 i에 차량별 누적 주차시간을 할당
        for (i in ptSumMap.toSortedMap().values) { 
            // 누적 주차 시간이 기본 시간이내라면 기본 요금 청구
            if (i < bt) res.add(bm)
            // 누적 주차 시간이 기본 시간을 초과했다면 초과한 시간에 대한 요금 계산
            else res.add((bm + ceil((i - bt) / ut.toDouble()) * um).toInt())
        }

        return res // 모든 차량의 주차요금 반환
    }
}

주어진 입/출차 기록을 바탕으로 각 차량별 주차 요금을

계산하고 리스트로 반환하는 로직이다.

 

 

ceil 함수

fun main() {
    fun ceil(number: Double): Double {
        val intValue = number.toInt()
        return if(number>0) intValue + 1.0 else intValue.toDouble()
    }
    println(ceil(1.1)) // 2.0
    println(ceil(-1.1)) // -1.0
}

 

ceil 함수는 인자로 받은 실수형 값의 소수점 이하를 올림 처리한다.

 

number(실수)의 올림을 진행하려면

number를 정수로 변환해 소수점 자리를 제거하고 1을 더해주면 된다.

number가 음수일 때는 반대로 소수점 자리만을 제거한다.

 

코드 길어지는게 싫어서 kotlin.math 라이브러리를 갖다 썼다.

 

 

회고

이떄까지 배웠던 개념들을 복습할 수 있었던 문제였다.

 

배열 요소를 어떤식으로 가공해야되는지 확인하기 위해

온라인 코틀린 디버거를 활용하여 예제코드를 작성해가며 풀었다.

 

문제 설명이 너무 길어서 필요한 부분만 잘랐는데 

이번 문제는 설명이 역대급 고봉밥이다. (궁금하면 확인 ㄱㄱ)

 


 

챌린지반 1주차 세션 정리

 

객체란?

객체는 상태와 행동을 가지는 개체를 말한다.

상태는 객체의 속성이며, 이는 변수를 통해 표현된다.
행동은 객체가 수행하는 메소드에 해당한다.

 

 

버스의 상태와 행동

 

버스의 상태에는 출발지, 도착지, 사용하는 연 종류, 수용 가능한 최대 인원 등이 있다.

버스의 행동에는 시동 걸기와 같은 기본적인 액션이 있다.

 

 

버스의 부모 클래스 생성

 

모든 버스의 클래스를 하나하나 만드는 것은 비효율적이다.

그래서 모든 버스가 공통적으로 상태와 행동을 포함한 부모 클래스를 만들어야 한다.

각각의 버스 클래스는 해당 부모 클래스를 상속받아

각각의 차이점을 기반으로 구현한다.

 

 

리스트 타입


리스트의 제네릭 타입은 생성한 클래스로도 정의할 수 있다.


리스트에 명시해둔 제네릭 타입과 일치하지 않는

클래스가 들어올 때 에러가 발생하게 된다.

 

 

터미널에서 특정버스 골라내기

버스 클래스에서 번호판(문자열)을 생성자로 정의한다.

Bus를 상속하는 자식 클래스들도 번호판을 생성자로 받아야 한다.

 

각각의 객체에 유일성을 부여하는 변수를 만들어줌으로써

객체들의 구분이 가능해진다.

 

 

버스 경유지 변경

 

public 변수로 경유지와 도착지를 생성자에 정의해준다.

버스 경유지를 클래스를 생성하는 시점에서만 변경할 수 있도록 해준다.

 

val로 생성자의 매개변수를 정의하게 되면 해당 변수는

클래스를 처음 생성할 때를 제외하고, 값을 변경할 수 없게 된다.

 

이런 거 고려해서 짜야 알아서 갖다 쓰는게 가능한 클래스를 설계할 수 있게 된다.

 

 

터미널에 시내버스 못들어가게 하기

 

EnterTerminal이란 인터페이스를 지정하고 

CityBus를 제외한 나머지 버스가 해당 인터페이스를 상속하도록 한다.

 

그 후 터미널 리스트의 제네릭 타입을 해당 인터페이스로 정의하면

CityBus를 터미널에 넣으려 할 때 에러가 발생하게 된다.

 

 

내부에서 쓰이는 변수 숨기기

 

 클래스의 프로퍼티를 private로 정의하면

외부에서 접근하지 못하게 할 수 있다.

 

 

추상클래스 

 

클래스를 abstract로 정의하게 되면 해당 클래스는 추상클래스가 되며,

추상클래스는 직접적으로 인스턴스화가 불가능하다.

 

추상 클래스는 자식 클래스가 반드시 구현해야할 메소드인

추상 메소드를 정의할 수 있는 클래스이다.

자식 메소드는 추상 메소드를 반드시 오버라이딩 해야한다.

 

 

클래스를 구현하는 이유

각각의 객체의 공통점과 차이점을 찾아 클래스를 구현하게 되면

구현할 객체가 많을 때 좀 더 편하게 코드를 작성할수 있게 된다. 

 

 

회고

주위 사물을 객체화하는 과정을 보면서

객체지향 프로그래밍을 하는 이유를 알게되었다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함