알고리즘
[Javascript] 프로그래머스 - 야근 지수
J3SUNG
2025. 3. 21. 18:40
728x90
문제 설명
하나의 작업은 1시간에 1만큼 처리할 수 있으며, 퇴근까지 남은 시간 N시간 동안 일의 작업량을 분배하여 남은 일의 작업량의 제곱 합(야근 피로도)을 최소화해야 합니다. 작업량이 클수록 야근 피로도에 더 큰 영향을 주기 때문에, 가장 큰 작업량부터 줄이는 방식이 효율적입니다.
제한 사항
- works는 길이 1 이상, 20,000 이하인 배열입니다.
- works의 원소는 50,000 이하인 자연수입니다.
- n은 1,000,000 이하인 자연수입니다.
해결 방법
알고리즘: 우선순위 큐 (Max Heap)
가장 많은 작업량부터 줄이기 위해 최대 힙을 사용합니다.
- 모든 작업량을 최대 힙에 삽입합니다.
- 남은 시간이 있는 동안, 가장 큰 작업량을 꺼내 1만큼 줄인 뒤 다시 힙에 삽입합니다.
- 작업량이 0 이하가 되더라도 힙에 삽입하며, 이후 정답 계산 시 0 이하 작업량은 0으로 처리합니다.
- 모든 작업량을 꺼내 제곱한 값을 누적하여 반환합니다.
시간 복잡도
- 최대 힙 삽입 및 제거 연산: O(log N)
- 최대 N번의 연산을 하므로 전체 시간 복잡도는 O(N log W), 여기서 W는 works의 길이입니다.
구현 코드
class MaxHeap {
constructor() {
this.heap = [];
}
push(value) {
this.heap.push(value);
let i = this.heap.length - 1;
while (i > 0) {
let p = Math.floor((i - 1) / 2);
if (this.heap[p] >= this.heap[i]) break;
[this.heap[i], this.heap[p]] = [this.heap[p], this.heap[i]];
i = p;
}
}
pop() {
if (this.heap.length === 0) return 0;
const top = this.heap[0];
const last = this.heap.pop();
if (this.heap.length === 0) return top;
this.heap[0] = last;
let i = 0;
const n = this.heap.length;
while (true) {
let left = 2 * i + 1,
right = 2 * i + 2,
largest = i;
if (left < n && this.heap[left] > this.heap[largest]) largest = left;
if (right < n && this.heap[right] > this.heap[largest]) largest = right;
if (largest === i) break;
[this.heap[i], this.heap[largest]] = [this.heap[largest], this.heap[i]];
i = largest;
}
return top;
}
}
function solution(n, works) {
let answer = 0;
const pq = new MaxHeap();
for (const work of works) {
pq.push(work);
}
while (n > 0) {
let work = pq.pop();
--work;
--n;
pq.push(work);
}
while (pq.heap.length > 0) {
const work = pq.pop();
answer += work <= 0 ? 0 : work ** 2;
}
return answer;
}