본문 바로가기

코딩 테스트/프로그래머스

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

프로그래머스

2022 KAKAO BLIND RECRUITMENT

 

 

프로그래머스

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

programmers.co.kr

주차 요금 계산

 

문제 정리
1. 주차장의 요금표와 차량이 입차, 출차 기록이 주어진다 -> 차량별로 주차 요금 계산하기
2. 입차된 후에 출차된 내역이 없다면, 23:59분에 출차된 것으로 간주
3. 차량 번호가 작은 자동차부터 청구할 주차 요금을 정수 배열에 return
4. records원소는 "시간 차량번호 내역" 문자열
5. 같은 시간에, 같은 차량 번호의 내역이 2번 이상 나타나지 않는다.
6. 주차장에 없는 차량이 출차되는 경우 x, 주차장에 이미 있는 차량이 다시 입차되는 경우 X

 

 

시작하기 전 접근 방법
1. 차량 번호와 입차,출차 시간을 담는 리스트 HashMap 생성 (차량 번호를 key로 같고 시간과 쌍을 이루기 위해)
2. 유일키인 차량 번호와 누적된 요금을 담을 TreeMap 생성 ( 차량 번호를 기준으로 오름차순 정렬 하기 위해 → 문제에서 차량번호순으로 정수 배열을 return 하기 위해서)
3. "시간 차량번호 내역" 문자열로 들어오는 것을 나눠서 계산하기 위한 배열로 생성
4. 시간을 계산하기 위해 HH:MM으로 이루어진 시간을 분단위로 변형하여 계산
5. 입차 기록이 있는 차와 입차 기록이 없는 차를 기준으로 분류해서 시간을 계산해 TreeMap에 시간 저장
6. 출차 기록이 없다면 23:59분에 출차 된것으로 시간 계산
7. 주차 요금을 나타내는 정수 배열을 이용하여 요금 계산

 

 

테스트 예제 값

 

 

 

1. 주차한 차들의 번호와 시간을 갖는 리스트인 HashMap parking과  차들의 번호와 누적된 요금을 계산하기 위한 시간을 갖는 리스트 (TreeMap으로 키 (차량번호) 기준 오름차순 정렬하기 위해여 생성)
Map<String, Integer> parking = new HashMap<>();
Map<String, Integer> costs = new TreeMap<>();

 

 

2. "시간 차량번호 내역"으로 주어진 문자열을 split를 이용하여 나눠 배열에 저장한다. 
3. (2) 인덱스에 해당하는 입차 출차 기준으로 입차할 경우 계산할 것이 없고 주차장에 있는 차량 번호와 시간을 저장해야 하기 때문에 바로 map에 차량번호와 시간을 저장한다.
4. 이용 시간을 계산해야 하므로 출차 기준으로 시간을 계산한다.
4-1. 이전 주차장 이용 기록이 없는 차라면 기존 map에 있는 입차 시간과 계산하여 차량번호와 시간을 계산하여 TreeMap에 시간을 저장한다.
4-2. 주차장 이용 기록이 있는 차라면 TreeMap에 있는 시간과 새로 이용한 시간을 계산하여 누적해서 다시 저장한다.
4-3. 출차가 된 차는 이제 HashMap에서 삭제한다. 
for (String r : records) {
	String[] record = r.split(" ");
	int time = getTime(record[0]); // 출차 시간
	String carNum = record[1]; // 차량번호
	String io = record[2]; // 출입
 
	if (io.equals("IN")) {
		parking.put(carNum, time);
	}
	if (io.equals("OUT")) {
		if (!costs.containsKey(carNum)) {
			costs.put(carNum, time - parking.get(carNum));
		} else {
			costs.put(carNum, costs.get(carNum) + time - parking.get(carNum));
		} 
		parking.remove(carNum);
	}
}

 

 

5. 윗 코드에서 사용된 getTime 메서드를 만들어야 한다.
해당 메서드는 문자열로 되어 있는 HH:MM을 나중에 시간 계산을 편리하게 하기 위하여 int형으로 바꾸고 시간을 분으로 계산하는 메서드이다.
→ split을 이용하여 시, 분으로 나누고 시*60+분을 하여 분단위로 맞춘다.
→ Integer.parseInt를 이용하여 String을 int로 변환
private static int getTime(String time) {
	String[] t = time.split(":");
	return Integer.parseInt(t[0]) * 60 + Integer.parseInt(t[1]);
}

 

 

6.  2~4번을 진행하는 과정에서 IN(입차)는 있지만 OUT(출차)가 없어 주차장에 남아 있는 차량에 대한 시간을 계산하는 것이다.
HashMap에 있는 차량 번호를 가져오기 위한 반복문을 수행한다.
누적 시간을 담고 있는 TreeMap에서 누적된 시간을 가져온다.
누적된 시간이 없는 차량번호라면 o을 리턴하고 누적된 시간이 있다면 기존 누적시간을 사용한다.
마지막 시간인 23:59분을 기준으로 시간을 계산하여 TreeMap에 시간을 저장한다.

 

if (!parking.isEmpty()) {
	for (String carNum : parking.keySet()) {
	Integer cost = costs.get(carNum);
	cost = (cost == null) ? 0 : cost;
	costs.put(carNum, cost + (23 * 60 + 59) - parking.get(carNum));
	}
}

 

 

7. fees배열을 이용하여 최종 요금을 계산하는 코드이다.
71. TreeMap에 크기만큼 차량이 주차장을 이용했기 때문에 해당 크기 만큼 ArrayList를 생성한다.
7-2. TreeMap에 있는 각 차량의 누적 시간만큼 반복문을 수행하며 fees에 배열에 값을 변수로 선언한다.
7-3. 요금 = 기본요금 + ((min-기본시간) / 단위시간) * 단위요금이므로 계산한다.
7-3-1. 누적 시간이 기본 주차 시간 이내라면 기본요금을 list에 추가
7-3-2. 누적 시간이 기본시간 초과할 경우 시간을 계산하여 소수점일 경우 올림 하여 요금을 계산하며 최종 요금을 정수로 형변환한다.
7-4. 계산된 요금을 list에 저장했기 때문에 문제는 int [] 배열로 존재하므로 배열로 변환하여 반환한다.
7-5. stream()과 mapToInt() 메서드를 사용하여 리스트요소를 정수형 배열로 반환한다.
List<Integer> answer = new ArrayList<>(costs.size());
        for (Integer c : costs.values()) {
            int basicTime = fees[0];
            int basicCharge = fees[1];
            int unitTime = fees[2];
            int unitCharge = fees[3];
 
            if (c <= basicTime) {
                answer.add(basicCharge) ;
            } else {
                answer.add((int) (basicCharge + Math.ceil((double) (c - basicTime) / unitTime) * unitCharge));
            }
        }
        return answer.stream().mapToInt(Integer::intValue).toArray();
    }

 

 

전체코드
더보기
import java.util.*;
class Solution {
    public int[] solution(int[] fees, String[] records) {
        Map<String, Integer> parking = new HashMap<>();
        Map<String, Integer> costs = new TreeMap<>();
        
         for (String r : records) {
            String[] record = r.split(" ");
            int time = getTime(record[0]); 
            String carNum = record[1]; 
            String io = record[2]; 
 
            if (io.equals("IN")) {
                parking.put(carNum, time);
            }
            if (io.equals("OUT")) {
                if (!costs.containsKey(carNum)) {
                    costs.put(carNum, time - parking.get(carNum));// 한번 입출차한 기록이있다면 기존 시간에 새 시간 누적
                    costs.put(carNum, costs.get(carNum) + time - parking.get(carNum));
                } 
                parking.remove(carNum);
            }
        }
        if (!parking.isEmpty()) {
            for (String carNum : parking.keySet()) {
                Integer cost = costs.get(carNum);
                cost = (cost == null) ? 0 : cost;
                costs.put(carNum, cost + (23 * 60 + 59) - parking.get(carNum));
            }
        }
        
        List<Integer> answer = new ArrayList<>(costs.size());
        for (Integer c : costs.values()) {
            int basicTime = fees[0];
            int basicCharge = fees[1];
            int unitTime = fees[2];
            int unitCharge = fees[3];
 
            if (c <= basicTime) {
                answer.add(basicCharge) ;
            } else {
                answer.add((int) (basicCharge + Math.ceil((double) (c - basicTime) / unitTime) * unitCharge));
            }
        }
        return answer.stream().mapToInt(Integer::intValue).toArray();
    }
    

    private static int getTime(String time) {
        String[] t = time.split(":");
        return Integer.parseInt(t[0]) * 60 + Integer.parseInt(t[1]);
    }
}