class MaxHeap {
constructor() {
this.heap = [null];
}
push(value) {
this.heap.push(value);
let currentIndex = this.heap.length - 1;
let parentIndex = Math.floor(currentIndex / 2);
while (parentIndex !== 0 && this.heap[parentIndex] < value) {
const temp = this.heap[parentIndex];
this.heap[parentIndex] = value;
this.heap[currentIndex] = temp;
currentIndex = parentIndex;
parentIndex = Math.floor(currentIndex / 2);
}
}
pop() {
if (this.heap.length === 2) return this.heap.pop(); // 루트 정점만 남은 경우
const returnValue = this.heap[1];
this.heap[1] = this.heap.pop();
let currentIndex = 1;
let leftIndex = 2;
let rightIndex = 3;
while (this.heap[currentIndex] < this.heap[leftIndex] ||
this.heap[currentIndex] < this.heap[rightIndex]) {
if (this.heap[leftIndex] < this.heap[rightIndex]) {
const temp = this.heap[currentIndex];
this.heap[currentIndex] = this.heap[rightIndex];
this.heap[rightIndex] = temp;
currentIndex = rightIndex;
} else {
const temp = this.heap[currentIndex];
this.heap[currentIndex] = this.heap[leftIndex];
this.heap[leftIndex] = temp;
currentIndex = leftIndex;
}
leftIndex = currentIndex * 2;
rightIndex = currentIndex * 2 + 1;
}
return returnValue;
}
}
function solution(no, works) {
// 모든 작업의 합보다 no가 크면 배상 비용을 낼 필요가 없다.
if (works.reduce((a, b) => a + b) <= no) {
return 0;
}
// max heap 구성
const heap = new MaxHeap();
for (const work of works) {
heap.push(work);
}
// no만큼 루프 돌면서 가장 큰 값을 빼서 처리 후 다시 push
for (let i = 0; i < no; i += 1) {
heap.push(heap.pop() - 1);
}
// 남은 요소에 제곱한 값들의 합을 구한 후 반환
return heap.heap.reduce((a, b) => a + b * b);
}
=> 처음에 최대값 추출해서 풀기, 매번 정렬해서 풀기를 선택했는데, 효율성 ㅁ측면에서 실패하였다. 매번 최대값을 추출할 때에는 힙 자료구조를 활용하는 것이 좋다. 힙은 이진 트리인데 요소가 추가되고 삭제 될 때마다 루트에 그 값이 갱신되기 때문에 logn 복잡도로 요구사항을 해결할 수 있다.