https://school.programmers.co.kr/learn/courses/30/lessons/92341
글은 엄청나게 긴데 구현 자체는 쉬운 문제. string으로 된 시간을 숫자로 바꾸고 적당히 계산. 번호판 같은 경우는 딕셔너리나 맵으로 대충 처리. 특이 케이스도 입차내역은 있는데 출차내역만 있는 경우만 조금 신경을 써주면 된다. 나는 관리하기 쉽게 class로 따로 정의해주고, 유니티로 게임 만들 때 썼던 딕셔너리 + 큐 조합으로 풀기로 했다. 그냥 배열을 써도 됐는데 시간은 좀 걸리더라고 깔끔하게 동작하는 게 마음에 더 들어서 그냥 그렇게 했다.
기본 클래스의 구현은 빠르게 만들었는데 버그 찾는 과정에서 엄청나게 많이 헤맸다. 첫 번째 실수는 숫자가 "11:10"으로 들어오는데 0,1,2,3번 참조를 해서 :를 숫자로 계산했다. 두 번째 실수는 단순히 계산 관련 실수. 추가 시간을 계산할 때 (사용 시간 - 기본 시간)으로 계산을 했는데, 이 경우 음수 값이 나올 수 있다는 사실을 간과했다. 그 와중에 변수명 실수도 좀 있어서 계산이 꼬이기도 했다. 마지막으로는 큐와 스택에 관한 실수. 기록이 큐로 쌓이게 했더니 이미 다 작성한 기록에 덮어쓰는 오류가 발생. 스택으로 바꿔서 해결했다. 코테를 본격적으로 보게 되면 IDE의 도움 없이 찾아야 하는데, 디버깅 믿고 너무 대충대충 코드를 짜는 게 아닌가 반성을 하게 되는 계기였다.
시간은 가독성만 신경 써서 어쩔 수 없는 듯.
using System;
using System.Collections.Generic;
using System.Linq;
public class Solution {
public class Record
{
public int inTime;
public int outTime = 23 * 60 + 59;
public static int baseTime;
public static int baseCost;
public static int addTime;
public static int addCost;
public Record(int time)
{
this.inTime = time;
}
public void SetOutTime(int time)
{
this.outTime = time;
}
public static void SetPay(int baseTime, int baseCost, int addTime, int addCost)
{
Record.baseTime = baseTime;
Record.baseCost = baseCost;
Record.addTime = addTime;
Record.addCost = addCost;
}
public int GetTime()
{
return outTime - inTime;
}
public static int CalcPay(int time)
{
var timeCalc = time - baseTime;
if (timeCalc < 1)
{
return baseCost;
}
var addTimeCalc = timeCalc / addTime;
int addCostCalc;
addTimeCalc = addTimeCalc < 1 ? 0 : addTimeCalc;
if (timeCalc % addTime == 0)
{
addCostCalc = addTimeCalc * addCost;
}
else
{
addCostCalc = (addTimeCalc + 1) * addCost;
}
return baseCost + addCostCalc;
}
}
public class Calc
{
private Dictionary<string, Stack<Record>> records = new Dictionary<string, Stack<Record>>();
public void AddRecord(string time, string number, string state)
{
var a = time[0] - '0';
var b = time[1] - '0';
var c = time[3] - '0';
var d = time[4] - '0';
var timeToInt = (a * 10 + b) * 60 + c * 10 + d;
if (!records.ContainsKey(number))
{
records[number] = new Stack<Record>();
}
if (state == "IN")
{
var newRecord = new Record(timeToInt);
records[number].Push(newRecord);
}
else
{
var findRecord = records[number].Pop();
findRecord.SetOutTime(timeToInt);
records[number].Push(findRecord);
}
}
public int[] GetResult()
{
var keys = records.Keys.OrderBy(i => i).ToArray();
int[] result = new int[keys.Length];
for (var i = 0; i < keys.Length; i++)
{
var recordQueue = records[keys[i]];
var recordTime = 0;
while (recordQueue.Count > 0)
{
var record = recordQueue.Pop();
recordTime += record.GetTime();
}
result[i] += Record.CalcPay(recordTime);
}
return result;
}
}
public int[] solution(int[] fees, string[] records) {
Record.SetPay(fees[0], fees[1], fees[2], fees[3]);
var calc = new Calc();
foreach (var t in records)
{
var split = t.Split(" ");
calc.AddRecord(split[0], split[1], split[2]);
}
return calc.GetResult();
}
}
기록 class에서 뜬금없이 비용을 계산하는 이유는 문제를 잘못 읽고 입차-출차 한 묶음마다 계산해야 하는 걸로 이해해서 그럼.