forked from neetcode-gh/leetcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: js - heap (neetcode-gh#686)
Co-authored-by: Mitchell Irvin <[email protected]>
- Loading branch information
1 parent
f8960f5
commit 23b6d27
Showing
9 changed files
with
436 additions
and
406 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
Oops, something went wrong.