알고리즘
[Javascript] 프로그래머스 - 디펜스 게임
J3SUNG
2025. 3. 4. 23:58
728x90
문제 설명
준호는 병사 n명을 가지고 연속되는 적의 공격을 막아야 합니다. 각 라운드에서는 enemy[i]명의 적이 등장하며, 남은 병사 중 해당 수만큼 소모하여 적을 막을 수 있습니다.
병사의 수보다 많은 적이 등장하면 게임이 종료됩니다.
또한, k번의 무적권을 사용하여 병사를 소모하지 않고 한 라운드의 공격을 막을 수 있습니다.
무적권을 적절히 사용하여 최대한 많은 라운드를 막는 것이 목표입니다.
제한 사항
- 1 ≤ n ≤ 1,000,000,000
- 1 ≤ k ≤ 500,000
- 1 ≤ enemy의 길이 ≤ 1,000,000
- 1 ≤ enemy[i] ≤ 1,000,000
- 모든 라운드를 막을 수 있다면 enemy.length를 반환
해결 방법
알고리즘: 우선순위 큐(최대 힙) 활용
- 각 라운드마다 등장하는 적의 수를 sum 변수에 누적하여 병사가 부족한지를 확인합니다.
- PriorityQueue(최대 힙)를 사용하여 현재까지 등장한 적 중 가장 많은 적을 저장합니다.
- 누적된 적의 수가 n을 초과하면, k번까지는 가장 큰 적의 수를 제거하여 무적권을 사용한 효과를 냅니다.
- 위 과정을 반복하며 최대한 많은 라운드를 버틸 수 있도록 합니다.
시간 복잡도
- 매 라운드마다 적을 PriorityQueue에 삽입 (O(log N))
- PriorityQueue에서 가장 큰 값을 제거하는 연산 (O(log N))
- enemy 배열의 길이를 M이라 할 때, 최악의 경우 O(M log M)
구현 코드
class MaxHeap {
constructor() {
this.heap = [];
}
swap(i, j) {
[this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]];
}
push(value) {
this.heap.push(value);
this.heapifyUp();
}
pop() {
if (this.heap.length === 1) return this.heap.pop();
const max = this.heap[0];
this.heap[0] = this.heap.pop();
this.heapifyDown();
return max;
}
heapifyUp() {
let index = this.heap.length - 1;
while (index > 0) {
let parentIndex = Math.floor((index - 1) / 2);
if (this.heap[parentIndex] >= this.heap[index]) break;
this.swap(parentIndex, index);
index = parentIndex;
}
}
heapifyDown() {
let index = 0;
let length = this.heap.length;
while (true) {
let leftChild = 2 * index + 1;
let rightChild = 2 * index + 2;
let largest = index;
if (leftChild < length && this.heap[leftChild] > this.heap[largest]) {
largest = leftChild;
}
if (rightChild < length && this.heap[rightChild] > this.heap[largest]) {
largest = rightChild;
}
if (largest === index) break;
this.swap(index, largest);
index = largest;
}
}
isEmpty() {
return this.heap.length === 0;
}
}
class PriorityQueue {
constructor() {
this.maxHeap = new MaxHeap();
}
enqueue(value) {
this.maxHeap.push(value);
}
dequeue() {
return this.maxHeap.pop();
}
isEmpty() {
return this.maxHeap.isEmpty();
}
}
function solution(n, k, enemy) {
let answer = 0;
const pq = new PriorityQueue();
let sum = 0;
for (let i = 0; i < enemy.length; ++i) {
sum += enemy[i];
pq.enqueue(enemy[i]);
if (sum > n) {
if (k <= 0) break;
sum -= pq.dequeue();
--k;
}
++answer;
}
return answer;
}