📌 문제
프로그래머스 팀에서는 기능 개선 작업을 수행 중입니다. 각 기능은 진도가 100%일 때 서비스에 반영할 수 있습니다.
또, 각 기능의 개발속도는 모두 다르기 때문에 뒤에 있는 기능이 앞에 있는 기능보다 먼저 개발될 수 있고, 이때 뒤에 있는 기능은 앞에 있는 기능이 배포될 때 함께 배포됩니다.
먼저 배포되어야 하는 순서대로 작업의 진도가 적힌 정수 배열 progresses와 각 작업의 개발 속도가 적힌 정수 배열 speeds가 주어질 때 각 배포마다 몇 개의 기능이 배포되는지를 return 하도록 solution 함수를 완성하세요.
📌 제한사항
- 작업의 개수(progresses, speeds배열의 길이)는 100개 이하입니다.
- 작업 진도는 100 미만의 자연수입니다.
- 작업 속도는 100 이하의 자연수입니다.
- 배포는 하루에 한 번만 할 수 있으며, 하루의 끝에 이루어진다고 가정합니다. 예를 들어 진도율이 95%인 작업의 개발 속도가 하루에 4%라면 배포는 2일 뒤에 이루어집니다.
📌 풀이
알아야 하는 것
- Math.ceil() : 주어진 숫자를 무조건 올림처리 해준다. (ex. Math.ceil(0.95) -> 1)
구할 것
TC : progresses = [93, 30, 55] / speeds = [1, 30, 5]
1) 필요한 진행 속도를 구한다.
현재 각 기능의 개발 진도는 93, 30, 55로, 100%를 기준으로 했을 때 얼마가 더 필요한지 계산한다.
필요한 만큼의 개발 진도를 채우려면 며칠이 걸리는지 계산하기 위함이다.
progresses의 각 개발 진도를 꺼내 100에서 빼주었다.
needSpeed = [7, 70, 45]가 되었다.
2) 진행 속도를 채우기 위해 필요한 날을 구한다.
speeds = [1, 30, 5]로 하루에 각각 1%, 30%, 5% 씩 개발을 할 수 있다.
7, 70, 45로 각 값을 나누었을 때 몫을 구하면 며칠이 필요한지 알 수 있다.
needDay = [7, 2.333333..., 9] 가 된다.
하지만 2.3일은 없다. 딱 떨어지는 정수가 아니라면 소수점 자리는 무조건 올림을 해준다.
그럼 다시, needDay = [7, 3, 9]가 된다.
3) 앞의 기능이 배포될 날을 계산한다.
문제에서 뒤에 있는 기능은 앞에 있는 기능이 배포될 때 배포할 수 있다고 했다.
현재 7, 3, 9로 각 기능은 개발되는데 7일, 3일, 9일이 걸린다.
이 때 3일 짜리는 3일에 개발이 다 이뤄져도 앞에 기능이 7일이 걸려 똑같이 7일 후에 배포된다.
이처럼 만약 뒤의 인덱스가 앞의 인덱스보다 작다면 배열에서 작은 인덱스를 지우고 큰 인덱스로 갈아 끼워준다.
이를 위해 splice를 사용해 i+1 인덱스 1개를 제거하고, needDay[i] (=앞의 인덱스)를 추가해준다.
needDay = [7, 7, 9]가 되었다.
4) 배포 일마다 몇 개의 기능이 배포되는지 계산한다.
답은 [2, 1]로 7일에 2개, 9일에 1개가 배포된다.
이 부분이 의외로 구현하기가 어려웠다. Set을 쓰자니 그냥 7, 9가 되어버려서...
이 문제가 스택/큐인 점을 떠올려 보면 (이게 스택인가 싶긴 한데) 앞의 값과 뒤의 값이 같다면 1을 더해주고,
그렇지 않다면 그냥 1을 push하는 형태로 구현할 수 있을 것이라고 생각했다.
답을 반환할 배열 counts를 선언하고, needDay에 있는 한 해당 일에 1개는 배포되니 1을 디폴트로 설정했다.
앞뒤를 비교할 거라 length 범위를 1 줄여주고 for문을 돌렸을 때, 앞과 뒤가 같다면 1을 더해준다.
같지 않다면 1을 push하고 다시 1로 초기화를 해준다.
1번의 needDay가 짧으니 2번으로 예를 들어 needDay = [5, 10, 10, 10, 20, 20]이라고 할 때
5 !== 10이기에 else로 빠져 1 push
10 === 10이기에 if로 빠져 1+1 = 2
10 === 10이기에 if로 빠져 2+1 = 3
10 !== 20이기에 else로 빠져 3 push 후 1로 초기화
20 === 20이기에 if로 빠져 1+1 = 2
for문이 끝나고 마지막 2를 넣어주기 위해 for문 밖에서 push한다.
이렇게 counts를 반환하면 정답이 나온다.
function solution(progresses, speeds) {
let needSpeed = progresses.map((v) => {
return 100 - v;
});
let needDay = speeds.map((v, i) => {
return Math.ceil(needSpeed[i] / v);
});
for (let i = 0; i < needDay.length; i++) {
if (needDay[i + 1] < needDay[i]) {
needDay.splice(i + 1, 1, needDay[i]);
}
}
let counts = [];
let currentCount = 1;
for (let i = 0; i < needDay.length - 1; i++) {
if (needDay[i] === needDay[i + 1]) {
currentCount++;
} else {
counts.push(currentCount);
currentCount = 1;
}
}
counts.push(currentCount);
return counts;
}
엄청 어려운 문제는 아니었는데, 마지막에 중복된 값의 개수를 구하는 게 살짝 어려웠다.
내가 푼 풀이는 스택/큐와 직접적인 연관이 없을 뿐더러 상당히 풀어서 쓴 거였다.
다른 분들의 풀이를 보니 아직 멀었다는 생각이 든다.
function solution(progresses, speeds) {
let answer = [0];
let days = progresses.map((progress, index) => Math.ceil((100 - progress) / speeds[index]));
let maxDay = days[0];
for(let i = 0, j = 0; i< days.length; i++){
if(days[i] <= maxDay) {
answer[j] += 1;
} else {
maxDay = days[i];
answer[++j] = 1;
}
}
return answer;
}
이런 식으로 반복문 안에 2개의 변수를 선언할 수 있다는 것도 처음 알았다. ㅠㅠ
TC를 예시로 보면 days는 [7, 3, 9]이고, maxDay는 7로 시작한다.
for문을 돌 때 7은 첫 번째 if에 걸려 answer[j] = 0은 += 1이 되고, 3도 첫 번째 if에 걸려 += 1이 되어 총 2가 된다.
다음 9는 else에 걸려 maxDay = days[i] = 9가 되고, answer[++j] = 1로 answer[1] = 1으로 들어가게 된다.
그러면 [2, 1]로 최종 반환할 수 있다.
**추가** (23.07.05)
스택스럽게 풀어보자.
day는 7, 3, 9가 나오게 된다.
이 때 스택의 길이가 0이거나 스택의 제일 오른쪽 값이 day보다 작다면 스택에 day를 넣고 answer라는 정답 배열에 1을 넣는다. 스택의 길이가 0이거나 라는 조건을 주지 않으면 처음에 스택에 값을 넣을 수가 없다. 예컨대 7이 스택에 들어가고, answer에 1이 추가 된 상태에서 3을 만났다. if 조건에 해당하지 않으므로 answer[answer.length - 1] ++ 이 된다. 이 말은 3일짜리가 들어와도 앞에 7일짜리가 더 크면 7일에 개발이 되기 때문에 7일의 경우 2개가 개발된다는 소리다.
이후 9가 들어온다. if문의 조건 2번째에 해당되므로 stack에 9가 들어오고, answer에 1이 추가된다.
즉 stack의 경우 [7, 9]만 들어와 있고 answer는 [2, 1]이 들어온다.
function solution(progresses, speeds) {
const stack = []
const answer = []
for (let i = 0; i < progresses.length; i++) {
const day = Math.ceil((100 - progresses[i]) / speeds[i])
if (stack.length === 0 || stack[stack.length-1] < day) {
stack.push(day)
answer.push(1)
} else {
answer[answer.length-1]++
}
}
return answer
}
'⚙️ 코딩테스트' 카테고리의 다른 글
[JavaScript] 프로그래머스 코딩테스트 레벨 1 : 완주하지 못한 선수 (0) | 2023.06.09 |
---|---|
[JavaScript] 프로그래머스 코딩테스트 레벨 1 : 대충 만든 자판 (0) | 2023.06.07 |
[JavaScript] 프로그래머스 코딩테스트 레벨 1 : 둘만의 암호 (0) | 2023.06.07 |
[JavaScript] 프로그래머스 코딩테스트 레벨 1 : 과일 장수 (0) | 2023.06.06 |
[JavaScript] 프로그래머스 코딩테스트 레벨 1 : 문자열 나누기 (0) | 2023.06.05 |