1. 문제풀이
1) 문제, 근무 지옥에 빠진 푸앙이 (백준, 25593)
군대에 간 푸앙이는 4 교대 근무를 서게 된다. 근무 시간대는 08:00~12:00, 12:00~18:00, 18:00~22:00, 22:00~08:00 으로 각각 4, 6, 4, 10시간의 근무로 구성되어 있다.
푸앙이와 동기들은 근무 시간이 최대한 공평하게 배분되기를 원한다. 그래서 근무표 전체에서 각 인원의 근무 시간이 12시간 이하로 차이 나게 해서 최대 50주 치 근무표를 짜려고 한다.
푸앙이는 원래 똑똑해서 이 정도는 한눈에 계산이 가능했지만 어째서인지 푸앙이는 계산이 불가능해졌다. 푸앙이를 위해서 대신 근무표가 공평한지 계산해 주자.
입력
- 첫 번째 줄에 주의 개수인 N이 입력된다. (1≤N≤50)
- 둘째 줄부터 근무표가 주어진다.
- 각 주는 4개의 줄로 표현되며, 그중 첫째 줄은 각 날의 08:00~12:00에 근무하는 사람의 이름 또는 '-', 둘째 줄은 12:00~18:00, 셋째 줄은 18:00~22:00, 넷째 줄은 22:00~08:00을 나타낸다.
- '-'는 근무자가 없음을 의미한다. 근무자의 이름은 모두 알파벳 소문자로 이루어져 있고 20글자를 넘지 않는다.
- 각 날에는 4개의 시간대에 모두 근무자가 있거나 모두 근무자가 없다. 예를 들어 12:00~18:00에만 근무자가 있는 날은 없다.
- 근무표에 적히지 않은 근무자는 없으며, 근무자 수는 최대 100명이다.
출력
- 근무표가 공평하면 “Yes”를 아니면 “No”를 출력한다. 단, 아무도 근무하지 않을 경우 공평한 것으로 간주한다.
힌트
- 첫 번째 예제에서 둘째 주 첫날 08:00~12:00 근무자는 puang, 12:00~18:00 근무자는 cony, 18:00~22:00 근무자는 choco, 22:00~08:00 근무자는 choco이다.
- 두 번째 예제에서 둘째 주 첫날 08:00~12:00 근무자는 pangyo, 12:00~18:00 근무자는 moon, 18:00~22:00 근무자는 moon, 22:00~08:00 근무자는 leonard이다.
2) 해석
- 근무표가 공평하면 yes, 아니면 no 출력
- 공평의 기준 : 각 인원의 근무 시간이 12시간 이하로 차이 나게
- 첫 번째 줄 : 주의 개수 N
- 차이가 12시간 이상 발생하는지 체크 > 가장 적은 사람과 많은 사람
- 각 이름 별로 근무 시간 넣기 map, set
해당 문제는 푸는 것보다 해석하는데 더 힘들었다..
아무리 문제와 입력, 힌트를 봐도 뭔 말인지 모르겠더라ㅠㅠ
결국 gpt의 힘과 먼저 푼 선배님들의 힘을 빌려서 해석했다.
첫 줄에 나온 주의 개수가 4이므로, 근무표는 총 4개의 주가 입력됨 알 수 있다.
그리고 각 주는 4개의 줄로 표현된다.
첫 번째는 8~12시, 두 번째는 12~18시, 세 번째는 18~22시, 네 번째는 22~08시이다.
그리고 한 줄마다 공백을 구분으로 7개씩 값이 입력되는데, 이게 바로 날짜이다.
한 주에는 7일이 존재하기 때문에 7개씩 입력된다.
즉, 첫째 주 1, 2, 3, 4, 5 일은 근무자가 없고, 6일 날 부터 근무를 시작하게 된다.
6일날 8~12시 근무자는 pangyo, 12시~18시 근무자는 sally, 18~22시 근무자는 leonard, 22~08시 근무자는 edward가 된다.
3) 풀이
const fs = require("fs");
const input = fs.readFileSync("./index.txt").toString().trim().split("\n");
const N = input[0];
const TIME = {
1: 4,
2: 6,
3: 4,
4: 10,
};
let timeKey = 1; //근무시간 key
let schedule = new Map();
for (let i = 1; i <= N * 4; i++) {
const weekSchedule = input[i].split(" ");
const addTime = TIME[timeKey];
weekSchedule.forEach((name) => {
if (name === "-") return;
//name이 있는지 확인 > 있으면 +, 없으면 value
const preValue = schedule.get(name) || 0;
let value = preValue ? preValue + addTime : addTime;
schedule.set(name, value);
});
//timeKey 초기화
if (timeKey !== 4) timeKey++;
else timeKey = 1;
}
let times = [...schedule.values()];
if (times.length === 0) {
// 아무도 근무하지 않는 경우
result = "Yes";
} else {
const max = Math.max(...times);
const min = Math.min(...times);
result = max - min > 12 ? "No" : "Yes";
}
console.log(result);
근무표 대로 이름을 key로 시간을 value로 저장한 후, 가장 많은 시간과 적은 시간을 비교하여 출력해야겠다는 생각을 했다.
const N = input[0];
const TIME = {
1: 4,
2: 6,
3: 4,
4: 10,
};
let timeKey = 1; //근무시간 key
let schedule = new Map();
우선 N을 저장해 준다.
근무시간을 저장할 TIME 변수를 만들어준다.
그 후, timeKey를 생성해 준다.
timeKey를 통해서 각 줄에 맞는 시간을 추가해 줄 것이다.
근무자마다 일한 시간을 저장할 schedule도 생성해 준다.
for (let i = 1; i <= N * 4; i++) {
const weekSchedule = input[i].split(" ");
const addTime = TIME[timeKey];
weekSchedule.forEach((name) => {
if (name === "-") return;
//name이 있는지 확인 > 있으면 +, 없으면 value
const preValue = schedule.get(name) || 0;
let value = preValue ? preValue + addTime : addTime;
schedule.set(name, value);
});
//timeKey 초기화
if (timeKey !== 4) timeKey++;
else timeKey = 1;
}
이제 N*4만큼 반복문을 돌려준다.
여기서 4는 각 주가 4개의 줄로 표현되기 때문에 곱해준다.
weekSchedule은 각 주의, i번째 줄을 의미한다.
addTime은 더해줄 시간을 의미한다.
아까 저장한 TIME에서 timekey를 사용해 값을 저장해 준다.
timekey는 4번째 돌고 나면(한 주가 끝나면) 초기화해주고, 그게 아니라면 1씩 더해준다.
그리고 weekSchedule를 돌면서 근무자가 없다면 return, 근무자가 있으면 근무시간을 더해준다.
set을 이용해 name을 key로 시간을 value로 저장해 준다.
이전 근무시간이 있으면 더해서 추가해 준다.
let times = [...schedule.values()];
if (times.length === 0) {
// 아무도 근무하지 않는 경우
result = "Yes";
} else {
const max = Math.max(...times);
const min = Math.min(...times);
result = max - min > 12 ? "No" : "Yes";
}
console.log(result);
마지막으로 저장한 schedule의 값을 배열 형태로 저장해 준다.
이때 length가 없으면 아무도 근무하지 않는 경우이기 때문에 Yes를 리턴하도록 만들어준다.
(처음에 이걸 빼먹어서 계속 에러가 발생했다ㅠ)
그리고 가장 큰 수와 가장 작은 수를 뽑아내서 둘의 차이가 12가 넘으면 "No" 아니면 "Yes"를 출력해 준다.
가장 큰 수와 가장 작은 수의 차이가 12를 넘지 않으면 다른 것들도 12가 넘지 않기 때문에 해당 숫자만 비교해 주면 된다.
- 걸린 시간
10분보다 훨씬 더 걸림 ㅎㅎ
해석하는 것만 한 30-40분 걸린 거 같다,,
2. 리팩토링
const fs = require("fs");
const input = fs.readFileSync("./index.txt").toString().trim().split("\n");
const N = parseInt(input[0], 10); // 주의 개수
const TIME = [4, 5, 4, 10];
let schedule = new Map();
for (let i = 1; i <= N * 4; i++) {
const weekSchedule = input[i].split(" ");
const addTime = TIME[(i - 1) % 4]; // 4시간대 반복 순환
weekSchedule.forEach((name) => {
if (name === "-") return;
const preValue = schedule.get(name) || 0;
schedule.set(name, preValue + addTime);
});
}
let times = [...schedule.values()];
// 결과 계산
const result =
times.length === 0 || Math.max(...times) - Math.min(...times) <= 12
? "Yes"
: "No";
console.log(result);
const N = parseInt(input[0], 10); // 주의 개수
const TIME = [4, 5, 4, 10];
우선 주의 개수를 parseInt를 통해 명확히 숫자로 지정해 줬다.
TIME의 경우 굳이 object 형식으로 하지 않아도 될 것 같아서 배열로 수정해 줬다.
const addTime = TIME[(i - 1) % 4]; // 4시간대 반복 순환
그리고 timekey를 따로 만들지 않고 %로 수정했다.
4개의 시간이 반복적으로 순환되는 것이기 때문에 나머지를 TIME의 index로 설정하면 그에 맞는 시간을 가져올 수 있다.
schedule.set(name, preValue + addTime);
value 변수를 만들지 않고, 바로 set의 value로 값을 넣어줬다.
const result =
times.length === 0 || Math.max(...times) - Math.min(...times) <= 12
? "Yes"
: "No";
마지막으로 result는 삼항연산자로 수정해서 나타냈다.
시간복잡도와 공간복잡도는 비슷하지만, 백준에서 체크해 봤을 때 두 번째가 0.4초 빨랐다ㅎㅎ
리팩터링 한 게 좀 더 가독성이 좋아서 만족한다!!
3. 기타
문제를 풀 때 순간적으로 map이 생각나서 사용했는데, object로 해도 똑같을 것 같아서 차이점을 찾아봤다.
map은 데이터 key가 다양하거나, 삽입 순서가 중요한 경우, key의 개수를 쉽게 확인해야 할 때, map 메서드가 필요할 때
이럴 경우에만 사용하는 게 좋을 것 같다!
해당 문제는 단순히 값을 저장하는 것뿐이라서 굳이 map을 사용하지 않아도 괜찮았을 것 같다.
'Algorithm > 99클럽' 카테고리의 다른 글
[99클럽] 코딩테스트 스터디, 9일차 TIL - 비기너 (0) | 2024.11.06 |
---|---|
[99클럽] 코딩테스트 스터디, 8일차 TIL - 비기너 (0) | 2024.11.05 |
[99클럽] 코딩테스트 스터디, 6일차 TIL - 비기너 (1) | 2024.11.04 |
[99클럽] 코딩테스트 스터디, 5일차 "모스부호" TIL - 비기너 (feat. 백준에서 자바스크립트 사용하기) (0) | 2024.11.03 |
[99클럽] 코딩테스트 스터디, 4일차 TIL - 비기너 (1) | 2024.10.31 |