Skip to content

Commit

Permalink
refactor: js - heap (neetcode-gh#686)
Browse files Browse the repository at this point in the history
Co-authored-by: Mitchell Irvin <[email protected]>
  • Loading branch information
aakhtar3 and mitchellirvin authored Sep 19, 2022
1 parent f8960f5 commit 23b6d27
Show file tree
Hide file tree
Showing 9 changed files with 436 additions and 406 deletions.
94 changes: 27 additions & 67 deletions javascript/1046-Last-Stone-Weight.js
Original file line number Diff line number Diff line change
@@ -1,73 +1,33 @@
class Heap {
constructor(stones) {
this.heap = stones;
this.size = stones.length;
this.heapify(0);
}
right(pos) {
return 2 * pos + 2;
}
left(pos) {
return 2 * pos + 1;
}
isleaf(pos) {
if (2 * pos + 1 >= this.size) return true;
return false;
}
swap(a, b) {
let temp = this.heap[a];
this.heap[a] = this.heap[b];
this.heap[b] = temp;
}
fix(pos) {
if (this.isleaf(pos)) return;
let left = this.left(pos);
let right = this.right(pos);
let bigger = left;
if (right < this.size)
bigger = this.heap[left] > this.heap[right] ? left : right;
if (this.heap[pos] < this.heap[bigger]) {
this.swap(pos, bigger);
this.fix(bigger);
}
}
heapify(pos) {
if (this.isleaf(pos)) return;
this.heapify(this.left(pos));
this.heapify(this.right(pos));
this.fix(pos);
}
delete() {
this.swap(0, --this.size);
this.fix(0);
return this.heap[0];
}
insert(val) {
this.size++;
this.heap[this.size - 1] = val;
this.heapify(0);
}
peek() {
return this.heap[0];
}
}
/**
* https://leetcode.com/problems/last-stone-weight/
* Time O(N * log(N)) | Space O(N)
* @param {number[]} stones
* @return {number}
*/
var lastStoneWeight = function (stones) {
//use a max heap to pop off the top 2 stones at each time
//if result is 0 we can do nothing
//if the result is a new weight we can push it back to the heap
const heap = new Heap(stones);
while (heap.size > 1) {
let x = heap.peek();
heap.delete();
let y = heap.peek();
heap.delete();
const res = x - y;
if (res > 0) heap.insert(res);
}
if (heap.size) return heap.peek();
return 0;
const maxHeap = getMaxHeap(stones)

shrink(maxHeap)

return !maxHeap.isEmpty()
? maxHeap.front().element
: 0
};

const getMaxHeap = (stones, maxHeap = new MaxPriorityQueue()) => {
for (const stone of stones) {
maxHeap.enqueue(stone)
}

return maxHeap
}

const shrink = (maxHeap) => {
while (1 < maxHeap.size()) {
const [ x, y ] = [ maxHeap.dequeue().element, maxHeap.dequeue().element ]
const difference = x - y;

const isPositive = 0 < difference
if (isPositive) maxHeap.enqueue(difference);
}
}
39 changes: 0 additions & 39 deletions javascript/215-Kth-Largest-Element-in-an-Array.js

This file was deleted.

56 changes: 56 additions & 0 deletions javascript/295-Find-Median-From-Data-Stream.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* https://leetcode.com/problems/find-median-from-data-stream/
* Your MedianFinder object will be instantiated and called as such:
* var obj = new MedianFinder()
* obj.addNum(num)
* var param_2 = obj.findMedian()
*/
class MedianFinder {
constructor () {
this.maxHeap = new MaxPriorityQueue()
this.minHeap = new MinPriorityQueue()
}

/* Time O(log(N)) | Space (N) */
insertNum (num) {
this.addNum(num)
}

addNum (num, heap = this.getHeap(num)) {
heap.enqueue(num)
this.rebalance()
}

getHeap (num, { maxHeap, minHeap } = this) {
const isFirst = maxHeap.isEmpty()
const isGreater = num <= this.top(maxHeap);
const isMaxHeap = (isFirst || isGreater);
return (isMaxHeap)
? maxHeap
: minHeap
}

rebalance ({ maxHeap, minHeap } = this) {
const canShiftMax = (minHeap.size() + 1) < maxHeap.size()
if (canShiftMax) return minHeap.enqueue(maxHeap.dequeue().element)

const canShiftMin = maxHeap.size() < minHeap.size()
if (canShiftMin) return maxHeap.enqueue(minHeap.dequeue().element)
}

/* Time O(1) | Space (1) */
findMedian ({ maxHeap, minHeap } = this) {
const isEven = maxHeap.size() === minHeap.size()
return (isEven)
? this.average(maxHeap, minHeap)
: this.top(maxHeap)
}

average (maxHeap, minHeap) {
return (this.top(maxHeap) + this.top(minHeap)) / 2
}

top (heap) {
return heap.front()?.element || 0
}
}
84 changes: 48 additions & 36 deletions javascript/295-Find-Median-from-Data-Stream.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,56 @@
var MedianFinder = function () {
this.array = [];
};

/**
* @param {number} num
* @return {void}
/**
* https://leetcode.com/problems/find-median-from-data-stream/
* Your MedianFinder object will be instantiated and called as such:
* var obj = new MedianFinder()
* obj.addNum(num)
* var param_2 = obj.findMedian()
*/
MedianFinder.prototype.addNum = function (num) {
var low = 0;
var high = this.array.length - 1;
class MedianFinder {
constructor () {
this.maxHeap = new MaxPriorityQueue()
this.minHeap = new MinPriorityQueue()
}

while (low <= high) {
var mid = Math.floor((high + low) / 2);
/* Time O(log(N)) | Space (N) */
insertNum (num) {
this.addNum(num)
}

if (this.array[mid] < num) {
low = mid + 1;
} else {
high = mid - 1;
}
addNum (num, heap = this.getHeap(num)) {
heap.enqueue(num)
this.rebalance()
}

this.array.splice(low, 0, num);
};
getHeap (num, { maxHeap, minHeap } = this) {
const isFirst = maxHeap.isEmpty()
const isGreater = num <= this.top(maxHeap);
const isMaxHeap = (isFirst || isGreater);
return (isMaxHeap)
? maxHeap
: minHeap
}

/**
* @return {number}
*/
MedianFinder.prototype.findMedian = function () {
if (this.array.length % 2 === 0) {
var mid = this.array.length / 2;
return (this.array[mid] + this.array[mid - 1]) / 2;
} else {
var mid = Math.floor(this.array.length / 2);
return this.array[mid];
rebalance ({ maxHeap, minHeap } = this) {
const canShiftMax = (minHeap.size() + 1) < maxHeap.size()
if (canShiftMax) return minHeap.enqueue(maxHeap.dequeue().element)

const canShiftMin = maxHeap.size() < minHeap.size()
if (canShiftMin) return maxHeap.enqueue(minHeap.dequeue().element)
}
};

/**
* Your MedianFinder object will be instantiated and called as such:
* var obj = new MedianFinder()
* obj.addNum(num)
* var param_2 = obj.findMedian()
*/
/* Time O(1) | Space (1) */
findMedian ({ maxHeap, minHeap } = this) {
const isEven = maxHeap.size() === minHeap.size()
return (isEven)
? this.average(maxHeap, minHeap)
: this.top(maxHeap)
}

average (maxHeap, minHeap) {
return (this.top(maxHeap) + this.top(minHeap)) / 2
}

top (heap) {
return heap.front()?.element || 0
}
}
Loading

0 comments on commit 23b6d27

Please sign in to comment.