Created
October 13, 2019 01:56
-
-
Save Shaddyjr/3ae4edd88953fc43aae623cd8dd73c3c to your computer and use it in GitHub Desktop.
HackerRank "Find the Running Median"
This file contains hidden or 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
class Heap{ | |
constructor(){ | |
this.array = new Array(50000); | |
this.length = 0; | |
} | |
guardEmpty(){ | |
if(this.length === 0) throw Error("Heap is Empty"); | |
} | |
getValue(index){ | |
const item = this.array[index]; | |
return this.valueProperty ? item[this.valueProperty] : item; | |
} | |
peek(){ | |
this.guardEmpty(); | |
return this.getValue(0); | |
} | |
getParentIndex(childIndex){ // returns raw array index | |
if(childIndex<=0) return 0; | |
return Math.floor((childIndex + 1) / 2) - 1; | |
} | |
getChildIndex(parentIndex, right = false){ // returns raw array index | |
const leftChildIndex = (((parentIndex + 1) * 2) - 1) + right; | |
if(this.getValue(leftChildIndex) === undefined) return -1; // out of index range | |
return leftChildIndex; | |
} | |
getRightChildIndex(parentIndex){ | |
return this.getChildIndex(parentIndex, true); | |
} | |
getLeftChildIndex(parentIndex){ | |
return this.getChildIndex(parentIndex); | |
} | |
insert(item){ | |
this.array[this.length++] = item; | |
this.bubbleUp(this.length - 1); | |
} | |
removeTop(){ | |
this.guardEmpty(); | |
const out = this.peek(); | |
if(this.array.length === 1){ | |
this.array[--this.length] = undefined; | |
return out; | |
} | |
this.array[0] = this.array[--this.length]; | |
this.bubbleDown(0); | |
return out; | |
} | |
swap(i, j){ | |
const temp = this.array[i]; | |
this.array[i] = this.array[j]; | |
this.array[j] = temp; | |
} | |
bubbleUp(index){ | |
// get target val | |
// get parent index | |
// get parent val | |
// if parent - child relationship is wrong | |
// swap parent - child and call bubbleUp on parent | |
if(index <= 0) return; | |
const targetVal = this.getValue(index); | |
const parentIndex = this.getParentIndex(index); | |
const parentVal = this.getValue(parentIndex); | |
if(!this.isCorrectParentChildRelationship(parentVal, targetVal)){ | |
this.swap(parentIndex, index); | |
this.bubbleUp(parentIndex); | |
} | |
} | |
bubbleDown(parentIndex){ | |
// index assumed to be parent that may | |
// may not be in appropriate parent - child relation | |
// get value | |
// if left is incorrect relationship, swap and call bubbleDown on child | |
// reassign parent val to new val | |
// if right is incorrect relationship, swap and call bubbleDown on child | |
let parentVal = this.getValue(parentIndex); | |
const leftIndex = this.getLeftChildIndex(parentIndex); | |
const rightIndex = this.getRightChildIndex(parentIndex); | |
if(leftIndex > 0){ | |
const leftVal = this.getValue(leftIndex); | |
if(!this.isCorrectParentChildRelationship(parentVal, leftVal)){ | |
this.swap(parentIndex, leftIndex); | |
this.bubbleDown(leftIndex); | |
parentVal = leftVal; | |
} | |
} | |
if(rightIndex >=0){ | |
const rightVal = this.getValue(rightIndex); | |
if(!this.isCorrectParentChildRelationship(parentVal, rightVal)){ | |
this.swap(parentIndex, rightIndex); | |
this.bubbleDown(rightIndex); | |
} | |
} | |
} | |
isCorrectParentChildRelationship(parentVal, childVal){ | |
} | |
} | |
class MaxHeap extends Heap{ | |
constructor(valueProperty){ | |
super(valueProperty); | |
} | |
isCorrectParentChildRelationship(parentVal, childVal){ | |
return childVal < parentVal; | |
} | |
} | |
class MinHeap extends Heap{ | |
constructor(valueProperty){ | |
super(valueProperty); | |
} | |
isCorrectParentChildRelationship(parentVal, childVal){ | |
return parentVal < childVal; | |
} | |
} | |
class MedianHeap{ | |
constructor(){ | |
this.minHeap = new MinHeap; | |
this.maxHeap = new MaxHeap; | |
} | |
insert(val){ | |
const maxL = this.maxHeap.length; | |
const minL = this.minHeap.length; | |
if(maxL === 0){ | |
this.maxHeap.insert(val); | |
return; | |
} | |
// if heaps are same | |
if(maxL === minL){ | |
if(val < this.minHeap.peek()){ | |
this.maxHeap.insert(val); | |
}else{ | |
this.minHeap.insert(val); | |
this.maxHeap.insert(this.minHeap.removeTop()); | |
} | |
}else if(maxL > minL){ | |
if(val > this.maxHeap.peek()){ | |
this.minHeap.insert(val); | |
}else{ | |
this.maxHeap.insert(val); | |
this.minHeap.insert(this.maxHeap.removeTop()); | |
} | |
} // maxHeap always larger than min heap (no need for else) | |
} | |
avg(a,b){ | |
return (a + b) / 2; | |
} | |
getMedian(){ | |
if(this.maxHeap.length > this.minHeap.length){ | |
return this.maxHeap.peek(); | |
} | |
return this.avg(this.maxHeap.peek(), this.minHeap.peek()); | |
} | |
} | |
function formatNum(num){ | |
return num.toFixed(1); | |
} | |
function runningMedian(arr) { | |
const medianHeap = new MedianHeap(); | |
for(let i = 0;i < arr.length; i++){ | |
medianHeap.insert(arr[i]); | |
arr[i] = formatNum(medianHeap.getMedian()); | |
} | |
return arr; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment