Study
data-structure
coding-test
heap
42626

더 맵게 (opens in a new tab)

문제 해결 방법

  • minHeap(최소힙)의 root(peek) 값이 K 이상이 될 때까지 mix를 반복한다
    • mix는 가장 맵지 않은 음식 + (두 번째로 맵지 않은 음식 * 2)이다
  • enq시, 원소를 삽입한 후 heapify를 진행한다
    • curIdx 값이 0보다 크고, 부모 노드 값이 현재 노드의 값보다 클 경우, heapify를 진행한다
  • deq시, root 값을 제거한 후, root 자리에 마지막 원소를 삽입한다
    • curIdx * 2 + 1 값이 최소 힙의 사이즈보다 작을 경우, heapify를 진행한다
    • 이때, 현재 원소 값이 자식 원소 값보다 작은 경우, heapify 반복을 중단한다
  • mix의 최소 횟수를 리턴하고, 모든 음식의 스코빌 지수를 K 이상으로 만들 수 없는 경우에는 -1을 리턴한다

오답노트

  • deq() 함수 내에서 배열이 비었는지를 체크하는 로직이 존재하는지
  • 음식이 하나가 남았고 그 음식의 스코빌 지수가 K 미만인 경우를 고려했는지

코드

class MinHeap {
  #arr;
 
  constructor(els) {
    this.#arr = els ?? [];
  }
 
  enq(el) {
    this.#arr.push(el);
 
    let curIdx = this.#arr.length - 1;
    let parIdx = Math.floor((curIdx - 1) / 2);
 
    while (curIdx > 0 && this.#arr[parIdx] > this.#arr[curIdx]) {
      this._swap(curIdx, parIdx);
      curIdx = parIdx;
      parIdx = Math.floor((curIdx - 1) / 2);
    }
  }
 
  deq() {
    if (this.#arr.length === 0) return null;
    if (this.#arr.length === 1) return this.#arr.pop();
 
    const originRoot = this.#arr[0];
    this.#arr[0] = this.#arr.pop();
    let curIdx = 0;
 
    while (curIdx * 2 + 1 < this.#arr.length) {
      let childIdx =
        curIdx * 2 + 2 < this.#arr.length &&
        this.#arr[curIdx * 2 + 2] < this.#arr[curIdx * 2 + 1]
          ? curIdx * 2 + 2
          : curIdx * 2 + 1;
 
      if (this.#arr[curIdx] < this.#arr[childIdx]) {
        break;
      }
 
      this._swap(curIdx, childIdx);
      curIdx = childIdx;
    }
    return originRoot;
  }
 
  _swap(a, b) {
    const tmp = this.#arr[a];
    this.#arr[a] = this.#arr[b];
    this.#arr[b] = tmp;
  }
 
  get size() {
    return this.#arr.length;
  }
 
  get peek() {
    return this.#arr[0];
  }
}
 
function solution(scoville, K) {
  const minHeap = new MinHeap();
  let cnt = 0;
 
  for (let s of scoville) {
    minHeap.enq(s);
  }
 
  while (minHeap.size >= 2 && minHeap.peek < K) {
    const mixed = minHeap.deq() + minHeap.deq() * 2;
    minHeap.enq(mixed);
    cnt += 1;
  }
 
  return minHeap.peek >= K ? cnt : -1;
}

실패했던 코드

1차

  • deq() 함수 내에서 배열이 비었는지를 체크하는 로직이 존재하지 않았음
class MinHeap {
  #arr;
 
  constructor(els) {
    this.#arr = els ?? [];
  }
 
  enq(el) {
    let curIdx = this.#arr.length - 1;
    let parIdx = Math.floor((curIdx - 1) / 2);
 
    this.#arr.push(el);
 
    while (curIdx > 0 && this.#arr[parIdx] > this.#arr[curIdx]) {
      this._swap(curIdx, parIdx);
      curIdx = parIdx;
    }
  }
 
  deq() {
    const originRoot = this.#arr[0];
 
    this.#arr[0] = this.#arr.pop();
    let curIdx = 0;
 
    while (curIdx * 2 + 1 < this.#arr.length) {
      let childIdx =
        curIdx * 2 + 2 < this.#arr.length &&
        this.#arr[curIdx * 2 + 2] < this.#arr[curIdx * 2 + 1]
          ? curIdx * 2 + 2
          : curIdx * 2 + 1;
 
      if (this.#arr[curIdx] < this.#arr[childIdx]) {
        break;
      }
 
      this._swap(curIdx, childIdx);
      curIdx = childIdx;
    }
    return originRoot;
  }
 
  _swap(a, b) {
    const tmp = this.#arr[a];
    this.#arr[a] = this.#arr[b];
    this.#arr[b] = tmp;
  }
 
  get size() {
    return this.#arr.length;
  }
 
  get peek() {
    return this.#arr[0];
  }
}
 
function solution(scoville, K) {
  const minHeap = new MinHeap();
  let cnt = 0;
 
  for (let s of scoville) {
    minHeap.enq(s);
  }
 
  while (minHeap.size >= 2 && minHeap.peek < K) {
    const mixed = minHeap.deq() + minHeap.deq() * 2;
    minHeap.enq(mixed);
    cnt += 1;
  }
  return minHeap.peek >= K ? cnt : -1;
}

2차

  • 음식이 하나가 남았고 그 음식의 스코빌 지수가 K 미만인 경우를 고려하지 않음
class MinHeap {
  #arr;
 
  constructor(els) {
    this.#arr = els ?? [];
  }
 
  enq(el) {
    this.#arr.push(el);
 
    let curIdx = this.#arr.length - 1;
    let parIdx = Math.floor((curIdx - 1) / 2);
 
    while (curIdx > 0 && this.#arr[parIdx] > this.#arr[curIdx]) {
      this._swap(curIdx, parIdx);
      curIdx = parIdx;
    }
  }
 
  deq() {
    if (this.#arr.length === 0) return null; // 1차 에러코드 개선
    if (this.#arr.length === 1) return this.#arr.pop(); // 1차 에러코드 개선
 
    const originRoot = this.#arr[0];
    this.#arr[0] = this.#arr.pop();
    let curIdx = 0;
 
    while (curIdx * 2 + 1 < this.#arr.length) {
      let childIdx =
        curIdx * 2 + 2 < this.#arr.length &&
        this.#arr[curIdx * 2 + 2] < this.#arr[curIdx * 2 + 1]
          ? curIdx * 2 + 2
          : curIdx * 2 + 1;
 
      if (this.#arr[curIdx] < this.#arr[childIdx]) {
        break;
      }
 
      this._swap(curIdx, childIdx);
      curIdx = childIdx;
    }
    return originRoot;
  }
 
  _swap(a, b) {
    const tmp = this.#arr[a];
    this.#arr[a] = this.#arr[b];
    this.#arr[b] = tmp;
  }
 
  get size() {
    return this.#arr.length;
  }
 
  get peek() {
    return this.#arr[0];
  }
}
 
function solution(scoville, K) {
  const minHeap = new MinHeap();
  let cnt = 0;
 
  for (let s of scoville) {
    minHeap.enq(s);
  }
 
  while (minHeap.size >= 2 && minHeap.peek < K) {
    const mixed = minHeap.deq() + minHeap.deq() * 2;
    minHeap.enq(mixed);
    cnt += 1;
  }
 
  return minHeap.peek >= K ? cnt : -1;
}