Total Cost to Hire K Workers - Two Heaps [JS]

Description 

Solution: Two Heaps

Two min heaps, left and right.
Keep up to candidates number of candidates in each heap.
For each hire, pick the smallest candidate out of both heaps.

  • Remove the candidate from its heap.
  • Add the next worker into the heap.

k = number of workers to hirem = candidates
Time Complexity: O(m log(m) + k log(m)) 1048ms
Space Complexity: O(m) 97.7MB

var totalCost = function(costs, k, candidates) {
  let n = costs.length;
  let left = new PriorityQueue((a, b) => a[1] === b[1] ? a[0] - b[0] : a[1] - b[1]); // [index, cost]  
  let right = new PriorityQueue((a, b) => a[1] === b[1] ? a[0] - b[0] : a[1] - b[1]); // [index, cost]
  let l, r;
  for (l = 0; l < Math.min(n, candidates); l++) {
    left.add([l, costs[l]]);
  }
  for (r = n - 1; r >= Math.max(0, n - candidates) && r > l; r--) {
    right.add([r, costs[r]]);
  }
  
  let totalCost = 0;
  for (let i = 0; i < k; i++) {
    let [leftIndex, leftCost] = left.size > 0 ? left.top() : [Infinity, Infinity];
    let [rightIndex, rightCost] = right.size > 0 ? right.top() : [Infinity, Infinity];
    let pickFromLeft = leftCost === rightCost ? leftIndex < rightIndex : leftCost < rightCost;
    if (pickFromLeft) { // pick from left heap
      left.remove();
      if (l <= r) left.add([l, costs[l]]), l++;
      totalCost += leftCost;
    } else { // pick from right heap
      right.remove();
      if (r >= l) right.add([r, costs[r]]), r--;
      totalCost += rightCost;
    } 
  }
  return totalCost;
};

class PriorityQueue {
  constructor(comparator = ((a, b) => a - b)) {
    this.values = [];
    this.comparator = comparator;
    this.size = 0;
  }
  add(val) {
    this.size++;
    this.values.push(val);
    let idx = this.size - 1, parentIdx = Math.floor((idx - 1) / 2);
    while (parentIdx >= 0 && this.comparator(this.values[parentIdx], this.values[idx]) > 0) {
      [this.values[parentIdx], this.values[idx]] = [this.values[idx], this.values[parentIdx]];
      idx = parentIdx;
      parentIdx = Math.floor((idx - 1) / 2);
    }
  }
  remove() {
    if (this.size === 0) return -1;
    this.size--;
    if (this.size === 0) return this.values.pop();
    let removedVal = this.values[0];
    this.values[0] = this.values.pop();
    let idx = 0;
    while (idx < this.size && idx < Math.floor(this.size / 2)) {
      let leftIdx = idx * 2 + 1, rightIdx = idx * 2 + 2;
      if (rightIdx === this.size) {
        if (this.comparator(this.values[leftIdx], this.values[idx]) > 0) break;
        [this.values[leftIdx], this.values[idx]] = [this.values[idx], this.values[leftIdx]];
        idx = leftIdx;
      } else if (this.comparator(this.values[leftIdx], this.values[idx]) < 0 || this.comparator(this.values[rightIdx], this.values[idx]) < 0) {
        if (this.comparator(this.values[leftIdx], this.values[rightIdx]) <= 0) {
          [this.values[leftIdx], this.values[idx]] = [this.values[idx], this.values[leftIdx]];
          idx = leftIdx;
        } else {
          [this.values[rightIdx], this.values[idx]] = [this.values[idx], this.values[rightIdx]];
          idx = rightIdx;
        }
      } else {
        break;
      }
    }
    return removedVal;
  }
  top() {
    return this.values[0];
  }
  isEmpty() {
    return this.size === 0;
  }
}

Comments

Popular posts from this blog

Maximum Value of an Ordered Triplet II - Two Solutions [JS]

Maximum Sum of Distinct Subarrays With Length K - Sliding Window w/ Two Pointers & Set [JS]

Sum of Prefix Scores of Strings - Trie [JS]

Maximum Count of Positive Integer and Negative Integer - Binary Search [JS]

Count Subarrays With Median K - Count Left & Right Balance [JS]