Seren dev's blog
article thumbnail

https://school.programmers.co.kr/learn/courses/30/lessons/92341

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

풀이

주차장의 요금표와 차량이 들어오고(입차) 나간(출차) 기록이 주어졌을 때, 차량별로 주차 요금을 계산해야 한다.

이 때 차는 여러번 입출차를 할 수 있으므로, 각 차의 누적 주차 시간을 계산해서 최종적으로 요금을 계산해야 한다.

 

먼저 문제를 풀기위한 자료구조는 다음과 같다.

차 번호는 고유하므로 차 번호를 Key로, 차의 정보를 Value로 하는 Map을 생성한다.

    static class Car {
        int number; // 차 번호
        String inDate; // 최근 입차 시각
        int time = 0; // 누적 시간
        boolean flag = false; // 입차만 했으면 false, 출차까지 했으면 true
        
        public Car(int number, String inDate) {
            this.number = number;
            this.inDate = inDate;
        }
    }
    
    HashMap<Integer, Car> cars = new HashMap<>();

 

또한 차량 번호가 작은 자동차부터 주차 요금을 계산하여 출력해야 하므로 이를 위한 자료구조도 생성한다.

    static class CarCost implements Comparable<CarCost> {
        int number; // 차 번호
        int cost; // 요금
        
        public CarCost(int number, int cost) {
            this.number = number;
            this.cost = cost;
        }
        
        @Override
        public int compareTo(CarCost o) {
            return this.number - o.number;
        }
    }
    
    ArrayList<CarCost> carCosts = new ArrayList<>();

 

로직

1. 입차

- 이미 입출차 한 전적이 있는 차의 경우, cars에서 해당 Car 객체를 조회하여 입차 시각과 flag를 변경하고 cars에 다시 넣는다.

- 새로 입차하는 차의 경우, 새로운 Car 객체를 생성하여 cars에 추가한다.

2. 출차

- cars에서 해당 Car 객체를 조회하여 입차 시각을 가져와 주차 시간(분 단위)을 구한다.

- 해당 Car 객체의 time(누적 주차 시간)을 업데이트한 후 cars에 추가한다.

3. records(입출차 내역)에 따라 모두 처리한 후, 입차만 한 차의 경우를 찾아 23:59에 출차한 것으로 간주하여 누적 시간을 업데이트한다.

4. cars로부터 carCosts를 생성하여 각 차의 요금을 계산한 후 정렬한다.

5. carCosts를 사용하여 answer에 각 차의 요금을 저장한다.

코드

import java.util.*;

class Solution {
    static class Car {
        int number; // 차 번호
        String inDate; // 최근 입차 시각
        int time = 0; // 누적 시간
        boolean flag = false; // 입차만 했으면 false, 출차까지 했으면 true
        
        public Car(int number, String inDate) {
            this.number = number;
            this.inDate = inDate;
        }
    }
    
    static class CarCost implements Comparable<CarCost> {
        int number; // 차 번호
        int cost; // 요금
        
        public CarCost(int number, int cost) {
            this.number = number;
            this.cost = cost;
        }
        
        @Override
        public int compareTo(CarCost o) {
            return this.number - o.number;
        }
    }
    
    public int[] solution(int[] fees, String[] records) {
        HashMap<Integer, Car> cars = new HashMap<>();
        
        for (String record: records) {
            String[] datas = record.split(" ");
            int number = Integer.parseInt(datas[1]);
            
            if (datas[2].equals("IN")) {
                if (cars.containsKey(number)) { // 이미 입출차 한 전적이 있는 경우
                    Car car = cars.get(number);
                    car.inDate = datas[0]; // 입차 시각 변경
                    car.flag = false; // flag 변경
                    cars.put(number, car);
                } // 새로 입차하는 경우
                else cars.put(number, new Car(number, datas[0]));
            }
            else if (datas[2].equals("OUT")) {
                String inDate = cars.get(number).inDate;
                int time = caculateTime(inDate, datas[0]);
                
                Car car = cars.get(number);
                car.time += time; // 누적 시간 업데이트
                car.flag = true; // flag 변경
                cars.put(number, car);
            }
        }
        
        // 입차만 한 차의 경우 23:59에 출차한 것으로 간주하여 누적 시간 업데이트
        for (int number: cars.keySet()) {
            Car car = cars.get(number);
            if (car.flag) continue;
            
            int time = caculateTime(car.inDate, "23:59");
            
            car.time += time; // 누적 시간 업데이트
            car.flag = true; // flag 변경
            cars.put(number, car);
        }
        
        // cars로부터 carCosts를 생성하여 각 차의 요금 계산
        ArrayList<CarCost> carCosts = new ArrayList<>();
        for (int number: cars.keySet()) {
            Car car = cars.get(number);
            int cost = calculateCost(car.time, fees);
            carCosts.add(new CarCost(number, cost));
        }
        Collections.sort(carCosts);
        
        int[] answer = new int[carCosts.size()];
        for (int i = 0; i < answer.length; i++) {
            answer[i] = carCosts.get(i).cost;
        }
        return answer;
    }
    
    static int caculateTime(String inDate, String outDate) {
        String[] inDates = inDate.split(":");
        String[] outDates = outDate.split(":");
        int inHour = Integer.parseInt(inDates[0]);
        int inMinute = Integer.parseInt(inDates[1]);
        int outHour = Integer.parseInt(outDates[0]);
        int outMinute = Integer.parseInt(outDates[1]);
        
        return (outHour * 60 + outMinute) - (inHour * 60 + inMinute);
    }
    
    static int calculateCost(int time, int[] fees) {
        
        if (time <= fees[0]) {
            return fees[1];
        }
        int diffMinute = time - fees[0];
        return (int)(fees[1] + fees[3] * (Math.ceil((double)diffMinute/fees[2])));
    }
}

 

다른 풀이 1

차량번호가 작은 순대로 정렬하여 주차 요금을 계산하기 위한 자료구조 없이 HashMap 대신

TreeMap을 사용하면, key 순대로 자동 정렬된다.

import java.util.*;

class Solution {
    static class Car {
        int number; // 차 번호
        String inDate; // 최근 입차 시각
        int time = 0; // 누적 시간
        boolean flag = false; // 입차만 했으면 false, 출차까지 했으면 true
        
        public Car(int number, String inDate) {
            this.number = number;
            this.inDate = inDate;
        }
    }
    
    public int[] solution(int[] fees, String[] records) {
        TreeMap<Integer, Car> cars = new TreeMap<>();
        
        for (String record: records) {
            String[] datas = record.split(" ");
            int number = Integer.parseInt(datas[1]);
            
            if (datas[2].equals("IN")) {
                if (cars.containsKey(number)) { // 이미 입출차 한 전적이 있는 경우
                    Car car = cars.get(number);
                    car.inDate = datas[0]; // 입차 시각 변경
                    car.flag = false; // flag 변경
                    cars.put(number, car);
                } // 새로 입차하는 경우
                else cars.put(number, new Car(number, datas[0]));
            }
            else if (datas[2].equals("OUT")) {
                String inDate = cars.get(number).inDate;
                int time = caculateTime(inDate, datas[0]);
                
                Car car = cars.get(number);
                car.time += time; // 누적 시간 업데이트
                car.flag = true; // flag 변경
                cars.put(number, car);
            }
        }
        
        // 입차만 한 차의 경우 23:59에 출차한 것으로 간주하여 누적 시간 업데이트
        for (int number: cars.keySet()) {
            Car car = cars.get(number);
            if (car.flag) continue;
            
            int time = caculateTime(car.inDate, "23:59");
            
            car.time += time; // 누적 시간 업데이트
            car.flag = true; // flag 변경
            cars.put(number, car);
        }
        
        // cars로부터 각 차의 요금 계산
        int[] answer = new int[cars.size()];
        int idx = 0;
        for (int key: cars.keySet()) {
            Car car = cars.get(key);
            int cost = calculateCost(car.time, fees);
            answer[idx++] = cost;
        }
        
        return answer;
    }
    
    static int caculateTime(String inDate, String outDate) {
        String[] inDates = inDate.split(":");
        String[] outDates = outDate.split(":");
        int inHour = Integer.parseInt(inDates[0]);
        int inMinute = Integer.parseInt(inDates[1]);
        int outHour = Integer.parseInt(outDates[0]);
        int outMinute = Integer.parseInt(outDates[1]);
        
        return (outHour * 60 + outMinute) - (inHour * 60 + inMinute);
    }
    
    static int calculateCost(int time, int[] fees) {
        
        if (time <= fees[0]) {
            return fees[1];
        }
        int diffMinute = time - fees[0];
        return (int)(fees[1] + fees[3] * (Math.ceil((double)diffMinute/fees[2])));
    }
}

 

다른 풀이 2

- Car 객체를 따로 생성할 필요없이 (차번호, 누적 주차 시간)을 Key, Value로 하는 TreeMap<String, Integer> cars를 생성한다.

- 입차하는 경우에는 -, 출차하는 경우에는 +를 하여 누적 주차 시간을 업데이트한다.

- 추후 주차 요금을 계산하기 전에 입차만 한 차의 경우에는 1439분(23:59)을 더해야 한다.

import java.util.*;

class Solution {
    
    public int[] solution(int[] fees, String[] records) {
        TreeMap<String, Integer> cars = new TreeMap<>();
        
        for (String record: records) {
            String[] datas = record.split(" ");
            String number = datas[1];
            
            if (datas[2].equals("IN")) { // 입차
                int time = calculateTime(datas[0]);
                cars.put(number, cars.getOrDefault(number, 0) - time);
            }
            else if (datas[2].equals("OUT")) { // 출차
                int time = calculateTime(datas[0]);
                cars.put(number, cars.getOrDefault(number, 0) + time);
            }
        }
        
        // cars로부터 각 차의 요금 계산
        int[] answer = new int[cars.size()];
        int idx = 0;
        for (String number: cars.keySet()) {
            int time = cars.get(number);
            if (time <= 0) { // 입차만 한 차의 경우 23:59에 출차한 것으로 간주
                time += 1439;
            }
            
            answer[idx++] = calculateCost(time, fees);
        }
        
        return answer;
    }
    
    static int calculateTime(String date) {
        String[] dates = date.split(":");
        return Integer.parseInt(dates[0]) * 60 + Integer.parseInt(dates[1]);
    }
    
    static int calculateCost(int time, int[] fees) {
        if (time <= fees[0]) {
            return fees[1];
        }
        int diffMinute = time - fees[0];
        return (int)(fees[1] + fees[3] * (Math.ceil((double)diffMinute/fees[2])));
    }
}

 

왼쪽이 첫번째 풀이, 가운데가 다른 풀이1, 오른쪽이 다른 풀이 2

728x90
profile

Seren dev's blog

@Seren dev

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!