Algorithm

[Algorithm] λ””μŠ€ν¬ 컨트둀러

ghkdu2 2023. 3. 6. 11:03

πŸ“‹ 문제

ν•˜λ“œλ””μŠ€ν¬λŠ” ν•œ λ²ˆμ— ν•˜λ‚˜μ˜ μž‘μ—…λ§Œ μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ””μŠ€ν¬ 컨트둀러λ₯Ό κ΅¬ν˜„ν•˜λŠ” 방법은 μ—¬λŸ¬ κ°€μ§€κ°€ μžˆμŠ΅λ‹ˆλ‹€. κ°€μž₯ 일반적인 방법은 μš”μ²­μ΄ λ“€μ–΄μ˜¨ μˆœμ„œλŒ€λ‘œ μ²˜λ¦¬ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

예λ₯Όλ“€μ–΄

- 0ms μ‹œμ μ— 3msκ°€ μ†Œμš”λ˜λŠ” Aμž‘μ—… μš”μ²­
- 1ms μ‹œμ μ— 9msκ°€ μ†Œμš”λ˜λŠ” Bμž‘μ—… μš”μ²­
- 2ms μ‹œμ μ— 6msκ°€ μ†Œμš”λ˜λŠ” Cμž‘μ—… μš”μ²­

와 같은 μš”μ²­μ΄ λ“€μ–΄μ™”μŠ΅λ‹ˆλ‹€. 이λ₯Ό 그림으둜 ν‘œν˜„ν•˜λ©΄ μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

ν•œ λ²ˆμ— ν•˜λ‚˜μ˜ μš”μ²­λ§Œμ„ μˆ˜ν–‰ν•  수 있기 λ•Œλ¬Έμ— 각각의 μž‘μ—…μ„ μš”μ²­λ°›μ€ μˆœμ„œλŒ€λ‘œ μ²˜λ¦¬ν•˜λ©΄ λ‹€μŒκ³Ό 같이 처리 λ©λ‹ˆλ‹€.

- A: 3ms μ‹œμ μ— μž‘μ—… μ™„λ£Œ (μš”μ²­μ—μ„œ μ’…λ£ŒκΉŒμ§€ : 3ms)
- B: 1msλΆ€ν„° λŒ€κΈ°ν•˜λ‹€κ°€, 3ms μ‹œμ μ— μž‘μ—…μ„ μ‹œμž‘ν•΄μ„œ 12ms μ‹œμ μ— μž‘μ—… μ™„λ£Œ(μš”μ²­μ—μ„œ μ’…λ£ŒκΉŒμ§€ : 11ms)
- C: 2msλΆ€ν„° λŒ€κΈ°ν•˜λ‹€κ°€, 12ms μ‹œμ μ— μž‘μ—…μ„ μ‹œμž‘ν•΄μ„œ 18ms μ‹œμ μ— μž‘μ—… μ™„λ£Œ(μš”μ²­μ—μ„œ μ’…λ£ŒκΉŒμ§€ : 16ms)

이 λ•Œ 각 μž‘μ—…μ˜ μš”μ²­λΆ€ν„° μ’…λ£ŒκΉŒμ§€ κ±Έλ¦° μ‹œκ°„μ˜ 평균은 10ms(= (3 + 11 + 16) / 3)κ°€ λ©λ‹ˆλ‹€.

ν•˜μ§€λ§Œ A → C → B μˆœμ„œλŒ€λ‘œ μ²˜λ¦¬ν•˜λ©΄

- A: 3ms μ‹œμ μ— μž‘μ—… μ™„λ£Œ(μš”μ²­μ—μ„œ μ’…λ£ŒκΉŒμ§€ : 3ms)
- C: 2msλΆ€ν„° λŒ€κΈ°ν•˜λ‹€κ°€, 3ms μ‹œμ μ— μž‘μ—…μ„ μ‹œμž‘ν•΄μ„œ 9ms μ‹œμ μ— μž‘μ—… μ™„λ£Œ(μš”μ²­μ—μ„œ μ’…λ£ŒκΉŒμ§€ : 7ms)
- B: 1msλΆ€ν„° λŒ€κΈ°ν•˜λ‹€κ°€, 9ms μ‹œμ μ— μž‘μ—…μ„ μ‹œμž‘ν•΄μ„œ 18ms μ‹œμ μ— μž‘μ—… μ™„λ£Œ(μš”μ²­μ—μ„œ μ’…λ£ŒκΉŒμ§€ : 17ms)

μ΄λ ‡κ²Œ A → C → B의 μˆœμ„œλ‘œ μ²˜λ¦¬ν•˜λ©΄ 각 μž‘μ—…μ˜ μš”μ²­λΆ€ν„° μ’…λ£ŒκΉŒμ§€ κ±Έλ¦° μ‹œκ°„μ˜ 평균은 9ms(= (3 + 7 + 17) / 3)κ°€ λ©λ‹ˆλ‹€.

각 μž‘μ—…μ— λŒ€ν•΄ [μž‘μ—…μ΄ μš”μ²­λ˜λŠ” μ‹œμ , μž‘μ—…μ˜ μ†Œμš”μ‹œκ°„]을 담은 2차원 λ°°μ—΄ jobsκ°€ λ§€κ°œλ³€μˆ˜λ‘œ μ£Όμ–΄μ§ˆ λ•Œ, μž‘μ—…μ˜ μš”μ²­λΆ€ν„° μ’…λ£ŒκΉŒμ§€ κ±Έλ¦° μ‹œκ°„μ˜ 평균을 κ°€μž₯ μ€„μ΄λŠ” λ°©λ²•μœΌλ‘œ μ²˜λ¦¬ν•˜λ©΄ 평균이 μ–Όλ§ˆκ°€ λ˜λŠ”μ§€ return ν•˜λ„λ‘ solution ν•¨μˆ˜λ₯Ό μž‘μ„±ν•΄μ£Όμ„Έμš”. (단, μ†Œμˆ˜μ  μ΄ν•˜μ˜ μˆ˜λŠ” λ²„λ¦½λ‹ˆλ‹€)

 

μ œν•œ 사항

  • jobs의 κΈΈμ΄λŠ” 1 이상 500 μ΄ν•˜μž…λ‹ˆλ‹€.
  • jobs의 각 행은 ν•˜λ‚˜μ˜ μž‘μ—…μ— λŒ€ν•œ [μž‘μ—…μ΄ μš”μ²­λ˜λŠ” μ‹œμ , μž‘μ—…μ˜ μ†Œμš”μ‹œκ°„] μž…λ‹ˆλ‹€.
  • 각 μž‘μ—…μ— λŒ€ν•΄ μž‘μ—…μ΄ μš”μ²­λ˜λŠ” μ‹œκ°„μ€ 0 이상 1,000 μ΄ν•˜μž…λ‹ˆλ‹€.
  • 각 μž‘μ—…μ— λŒ€ν•΄ μž‘μ—…μ˜ μ†Œμš”μ‹œκ°„μ€ 1 이상 1,000 μ΄ν•˜μž…λ‹ˆλ‹€.
  • ν•˜λ“œλ””μŠ€ν¬κ°€ μž‘μ—…μ„ μˆ˜ν–‰ν•˜κ³  μžˆμ§€ μ•Šμ„ λ•Œμ—λŠ” λ¨Όμ € μš”μ²­μ΄ λ“€μ–΄μ˜¨ μž‘μ—…λΆ€ν„° μ²˜λ¦¬ν•©λ‹ˆλ‹€.

 

μž…μΆœλ ₯ 예

[[0, 3], [1, 9], [2, 6]] 9

 

✏️ 풀이

이 λ¬Έμ œμ—μ„œ κ°€μž₯ 쀑점은 μž‘μ—…μ˜ μš”μ²­μ‹œκ°„λΆ€ν„° μž‘μ—…μ΄ λλ‚˜λŠ” μ‹œκ°„μ΄ μ΅œμ†Œκ°€ λ˜λŠ” 것이라고 μƒκ°ν–ˆλ‹€. μ²˜μŒμ—λŠ” κ·Έλž˜ν”„ν™” μ‹œμΌœμ„œ μ •λ ¬ν•œ 이후 μ•žμ—μ„œλΆ€ν„° λΉΌμ£ΌλŠ” 방법을 μ‚¬μš©ν•΄λ³ΌκΉŒ ν–ˆλŠ”λ° μ‹œκ°„ 흐름과 μ–΄λ–€ μž‘μ—…μ„ ν–ˆμ„ λ•Œ μ΅œμ†Œκ°€ λ˜λŠ”μ§€ νŒλ³„ν•˜κΈ°κ°€ μ–΄λ €μ› λ‹€. κ·Έλž˜μ„œ jobs 배열을 λ¨Όμ € μ •λ ¬μ‹œν‚€κ³  μ‹œκ°„μ„ μ¦κ°€μ‹œν‚€λ©΄μ„œ ν˜„μž¬ ν•  수 μžˆλŠ” μž‘μ—…μ΄ μžˆμ„ λ•Œ κ°€μž₯ μ΅œμ†Œμ˜ μ†Œμš”μ‹œκ°„μ„ κ°€μ§€κ³  μžˆλŠ”(κ°€μž₯ μ΅œμ†Œ μ‹œκ°„) μž‘μ—…μ„ λΉΌμ€˜μ•Όκ² λ‹€κ³  μƒκ°ν–ˆλ‹€.

 

κ³„μ†ν•΄μ„œ 정렬을 μˆ˜ν–‰ν•˜κ²Œ 되면 μ΅œμ•…μ˜ 경우 1000!의 μ‹œκ°„μ΄ ν•„μš”ν•˜κΈ° λ•Œλ¬Έμ— μ‹œκ°„μ΄ˆκ³Όκ°€ 일어날 것이라고 μƒκ°ν–ˆκΈ° λ•Œλ¬Έμ— min heap을 μ‚¬μš©ν–ˆλ‹€ min heap은 μž‘μ—…μ˜ λ‚΄μš©(jobs λ°°μ—΄μ˜ μš”μ†Œ)λ₯Ό λ°›μ•„ 두 번째 μš”μ†Œ(μ†Œμš”μ‹œκ°„)을 κΈ°μ€€μœΌλ‘œ 제일 μ•ž μš”μ†Œκ°€ μž‘μ€ 값이 λ˜λ„λ‘ ν–ˆλ‹€.

while문을 λŒλ©΄μ„œ μ‹œκ°„μ„ μ¦κ°€μ‹œν‚€λŠ”λ° 남은 μž‘μ—…μ΄ μžˆμ„ λ•Œ(jobs.length || heap.size())κΉŒμ§€ λ°˜λ³΅ν–ˆλ‹€.  whileλ¬Έ ν•˜λ‚˜λ₯Ό 더 μ€‘μ²©μ‹œμΌœμ„œ ν˜„μž¬ μ‹œκ°„μ— ν•  수 μžˆλŠ” μž‘μ—…μ΄ μžˆμ„λ•Œ heap에 λ„£μ–΄μ€€λ‹€. 이후 if문으둜 ν˜„μž¬ μˆ˜ν–‰ν•  수 μžˆλŠ” μž‘μ—…μ΄ μžˆμ„ λ•Œ(heap.size()) heapμ—μ„œ λΉΌμ„œ 총 μ†Œμš”μ‹œκ°„μ— 더해쀬닀.

 

κ°€μž₯ μ™ΈλΆ€μ˜ while문이 μ’…λ£Œλ˜κ³ (λͺ¨λ“  μž‘μ—…μ„ μˆ˜ν–‰) answer에 총 μ†Œμš”μ‹œκ°„μ„ 총 μž‘μ—… 개수둜 λ‚˜λˆ μ£Όκ³  μ†Œμˆ˜μ  μ΄ν•˜λ₯Ό λ²„λ¦ΌμœΌλ‘œμ¨ 문제λ₯Ό ν•΄κ²°ν•  수 μžˆμ—ˆλ‹€.

 

⌨️ μ½”λ“œ

class MinHeap {
  constructor() {
    this.heap = [];
    this.heap.push(-1e9);
  }

  insert(value) {
    this.heap.push(value);
    this.upheap(this.heap.length - 1);
  }

  upheap(pos) {
    let temp = this.heap[pos];

    while (temp[1] < this.heap[parseInt(pos / 2)][1]) {
      this.heap[pos] = this.heap[parseInt(pos / 2)];
      pos = parseInt(pos / 2);
    }
    this.heap[pos] = temp;
  }

  get() {
    if (this.size() === 0) return 0;
    if (this.size() === 1) return this.heap.pop();
    const result = this.heap[1];
    this.heap[1] = this.heap.pop();
    this.downheap(1, this.heap.length - 1);
    return result;
  }

  downheap(pos, len) {
    let temp = this.heap[pos],
      child;
    while (pos <= parseInt(len / 2)) {
      child = pos * 2;
      if (child < len && this.heap[child][1] > this.heap[child + 1][1]) child++;
      if (temp[1] <= this.heap[child][1]) break;
      this.heap[pos] = this.heap[child];
      pos = child;
    }
    this.heap[pos] = temp;
  }

  size() {
    return this.heap.length - 1;
  }
}

function solution(jobs) {
  var answer = 0;

  const n = jobs.length;
  const heap = new MinHeap();
  jobs.sort((a, b) => b[0] - a[0]);

  let totalTime = 0;
  let s = 0;
  while (jobs.length || heap.size()) {
    while (jobs.length && jobs[jobs.length - 1][0] <= s) {
      const job = jobs.pop();
      heap.insert(job);
    }

    if (heap.size()) {
      const [start, time] = heap.get();
      totalTime += s + time - start;
      s += time;
    } else {
      s += 1;
    }
  }

  answer = Math.floor(totalTime / n);

  return answer;
}