I'm having trouble with one of my test cases and I can't figure out why. Any help would be appreciated. I tried implementing a min-heap with number types but something seems to be off. I tried to make the class as clear as possible. The expected order for a min-heap should be in ascending order when removing elements, for example: 1,2,3,4,5,6.
Min Heap Class:
class MinHeap {
constructor() {
this.heap = [];
}
getLeftChildIndex(parentIndex) { return 2 * parentIndex + 1; }
getRightChildIndex(parentIndex) { return 2 * parentIndex + 2; }
getParentIndex(childIndex) { return Math.floor((childIndex - 1) / 2); }
hasLeftChild(index) { return this.getLeftChildIndex(index) < this.heap.length; }
hasRightChild(index) { return this.getRightChildIndex(index) < this.heap.length; }
hasParent(index) { return this.getParentIndex(index) > 0 };
leftChild(index) { return this.heap[this.getLeftChildIndex(index)]; }
rightChild(index) { return this.heap[this.getRightChildIndex(index)]; }
parent(index) { return this.heap[this.getParentIndex(index)]; }
heapifyUp() {
var index = this.heap.length - 1;
while(this.hasParent(index) && this.parent(index) > this.heap[index]) {
this.swap(this.getParentIndex(index), index);
index = this.getParentIndex(index);
}
}
heapifyDown() {
var index = 0;
while(this.hasLeftChild(index)) {
var smallerChildIndex = this.getLeftChildIndex(index);
if(this.hasRightChild(index) && this.rightChild(index) < this.leftChild(index)) {
smallerChildIndex = this.getRightChildIndex(index);
}
if(this.heap[index] < this.heap[smallerChildIndex]) {
// No need to continue, we are in order
break;
}
this.swap(index, smallerChildIndex);
index = smallerChildIndex;
}
}
swap(index1, index2) {
var temp = this.heap[index1];
this.heap[index1] = this.heap[index2];
this.heap[index2] = temp;
}
peek() {
if(this.heap.length === 0) throw Error("Error: Heap underflow");
return this.heap[0];
}
getSize() {
return this.heap.length;
}
isEmpty() {
return this.heap.length === 0;
}
remove() {
if(this.heap.length === 0) throw Error("Error: Heap underflow");
var item = this.heap[0];
this.heap[0] = this.heap[this.heap.length - 1];
this.heap.pop();
this.heapifyDown();
return item;
}
add(item) {
this.heap.push(item);
this.heapifyUp();
}
}
Test Case Fail:
var heap = new MinHeap();
var list = [];
heap.add(1);
heap.add(1);
heap.add(2);
list.push(heap.remove());
heap.add(4);
list.push(heap.remove());
heap.add(3);
list.push(heap.remove());
heap.add(6);
list.push(heap.remove());
heap.add(3);
list.push(heap.remove());
heap.add(4);
list.push(heap.remove());
heap.add(5);
list.push(heap.remove());
list.push(heap.remove());
list.push(heap.remove());
console.log(list); // logs [1,1,2,3,4,3,4,5,6]
Something is wrong with my logic but can't seem to figure it out.
The problem is in the line
hasParent(index) { return this.getParentIndex(index) > 0 };
which should be
hasParent(index) { return this.getParentIndex(index) >= 0 };
or
hasParent(index) { return index > 0 };
With the broken implementation, adding 3 to the heap [4, 6] does not propagate it up properly, because index 2 is not considered to have a parent.
Bergi pointed our that, in this particular implementation, hasParent() could be simplified to an expression that's so minimal it's probably better to inline it.
For developers arriving at this question looking for a good way to program a min heap in JavaScript, I've worked on making an implementation that's as clear as possible:
class MinHeap {
constructor() {
this.data = [];
}
peak() {
return this.data[0];
}
push(value) {
this.data.push(value);
let i = this.data.length - 1;
while (i > 0) {
const parentIndex = Math.ceil((i / 2) - 1);
if (this.data[i] < this.data[parentIndex]) {
this.swap(i, parentIndex);
i = parentIndex;
} else {
break;
}
}
}
pop() {
// 1 or no remaining items is a special case
if (this.data.length < 2) {
return this.data.pop();
}
const min = this.data[0];
this.data[0] = this.data.pop();
let i = 0;
while (true) {
const [leftIndex, rightIndex] = [(i * 2) + 1, (i * 2) + 2];
const leftValue = this.data[leftIndex] ?? Infinity;
const rightValue = this.data[rightIndex] ?? Infinity;
// If both children are larger than the candidate, we're done.
if (leftValue > this.data[i] && rightValue > this.data[i]) {
break;
}
// Otherwise pick the index of the smallest value
const smallestIndex = leftValue < rightValue ? leftIndex : rightIndex;
this.swap(i, smallestIndex);
i = smallestIndex;
}
return min;
};
swap(i1, i2) {
const val1 = this.data[i1];
this.data[i1] = this.data[i2];
this.data[i2] = val1;
}
}
Usage and behavior:
const heap = new MinHeap();
heap.push(2);
heap.push(1);
heap.push(3);
heap.pop(); // 1
heap.pop(); // 2
heap.pop(); // 3
Suggestions for improvements is welcome! There is also a full explanation of the approach for people that aren't familiar with the array-backed-tree and "sink" and "float" heap algorithms.
Related
Here is the code which i tried to solve, for the leetcode problem in javaScript https://leetcode.com/problems/palindrome-number/
Problem i am facing:
It is working for even number of digits in an intArr, but not for odd.
let myFunc = (num) => Number(num);
var intArr = Array.from(String(myInt), myFunc);
console.log(intArr.length);
const half = Math.ceil(intArr.length / 2);
const firstHalf = intArr.splice(0, half);
const secondHalf = intArr.splice(-half).reverse();
if (intArr.length % 2 != 0) {
firstHalf.pop();
}
console.log(firstHalf);
console.log(secondHalf);
arrayEquals(firstHalf, secondHalf);
function arrayEquals(firstHalf, secondHalf) {
if (
Array.isArray(firstHalf) &&
Array.isArray(secondHalf) &&
firstHalf.length === secondHalf.length &&
firstHalf.every((val, index) => val === secondHalf[index])
) {
console.log("true");
} else {
console.log("false");
}
}
}
isPalindrome(1221);
isPalindrome(12321);
Please let me know how can i solve this problem.
Please correct me if I was wrong in implementing this solution, Thank you.
You can check weather a number or string is a Palindrome or not by using following Function
const isPalindrome = (input) => {
const arr = (input.toString()).split('');
let isPalindromeInput = true, inputLengthMid = Math.floor(arr.length / 2);
for(let i=0, j=arr.length - 1; i <= inputLengthMid && j >= inputLengthMid; i++, j--) {
if(arr[i].toLowerCase() !== arr[j].toLowerCase()){
isPalindromeInput = false;
break;
}
}
return isPalindromeInput;
}
console.log('isPalindrome : ', isPalindrome('Neveroddoreven'));
console.log('isPalindrome : ', isPalindrome(12321));
console.log('isPalindrome : ', isPalindrome(1221));
console.log('isPalindrome : ', isPalindrome(11214211));
My Code:
const crypto = require('crypto');
const crashHash = '';
// Hash from bitcoin block #610546. Public seed event: https://twitter.com/Roobet/status/1211800855223123968
const salt = '0000000000000000000fa3b65e43e4240d71762a5bf397d5304b2596d116859c';
function saltHash(hash) {
return crypto
.createHmac('sha256', hash)
.update(salt)
.digest('hex');
}
function generateHash(seed) {
return crypto
.createHash('sha256')
.update(seed)
.digest('hex');
}
function divisible(hash, mod) {
// We will read in 4 hex at a time, but the first chunk might be a bit smaller
// So ABCDEFGHIJ should be chunked like AB CDEF GHIJ
var val = 0;
var o = hash.length % 4;
for (var i = o > 0 ? o - 4 : 0; i < hash.length; i += 4) {
val = ((val << 16) + parseInt(hash.substring(i, i + 4), 16)) % mod;
}
return val === 0;
}
function crashPointFromHash(serverSeed) {
const hash = crypto
.createHmac('sha256', serverSeed)
.update(salt)
.digest('hex');
const hs = parseInt(100 / 4);
if (divisible(hash, hs)) {
return 1;
}
const h = parseInt(hash.slice(0, 52 / 4), 16);
const e = Math.pow(2, 52);
return Math.floor((100 * e - h) / (e - h)) / 100.0;
}
function getPreviousGames() {
const previousGames = [];
let gameHash = generateHash(crashHash);
for (let i = 0; i < 100; i++) {
const gameResult = crashPointFromHash(gameHash);
previousGames.push({ gameHash, gameResult });
gameHash = generateHash(gameHash);
}
return previousGames;
}
function verifyCrash() {
const gameResult = crashPointFromHash(crashHash);
const previousHundredGames = getPreviousGames();
return { gameResult, previousHundredGames };
}
console.log(verifyCrash());
Code Sandbox
I'm trying to make this code show the results it already shows, but I want it to add something to the end of each gameResult data so it would look like this: gameResult: 4.39 "maybe"
I've tried to add something like this to the code with no luck. I had it working to the point where it would only return the very first gameResult but not the ones after. If someone could help that would be great, or if you have another way other than this code below that I was trying to use, that works too.
function gameResult
const result =
if (gameResult === 1) {
return "no";
};
if (gameResult <= 3) {
return "maybe";
};
if (gameResult <= 10) {
return "yes";
};
So, if I understand correctly the expected output should be like this,
{
"gameResult": "4.39 "yes"",
"previousHundredGames": [...]
}
I am able to do this by modifying the verifyCrash function to this,
function verifyCrash() {
let gameResult = crashPointFromHash(crashHash);
const previousHundredGames = getPreviousGames();
if (gameResult === 1) {
gameResult=+' "no"';
}
if (gameResult <= 3) {
gameResult=+' "maybe"';
}
if (gameResult <= 10) {
gameResult+= ' "yes"';
}
return { gameResult, previousHundredGames };
}
Check this link to see it in action,
https://codesandbox.io/s/crash-forked-f7fb7
I have to do a binary search for a names directory in typescript, if the name is in the array the code works properly but if the name it's not in the array it became in an infinite loop.
Can somebody help me? Please!
This is the code:
var initialArray = ['Diego', 'David','Mauricio']
var sortedArray = initialArray.sort()
function search(find) {
var leftLimit = initialArray[0]
var leftLimitIndex = initialArray.indexOf(leftLimit)
var rightLimit = initialArray[initialArray.length - 1]
var rightLimitIndex = initialArray.indexOf(rightLimit)
var pivotIndex = 0
var index = -1
while (compare(leftLimit, rightLimit)) {
pivotIndex = Math.floor((leftLimitIndex + rightLimitIndex)/2)
console.log(pivotIndex)
if (initialArray[pivotIndex] == find) {
index = pivotIndex
break
}
else {
if (compare(initialArray[pivotIndex], find)) {
leftLimitIndex = pivotIndex + 1
}
else {
rightLimitIndex = pivotIndex - 1
}
}
console.log(initialArray[pivotIndex])
}
console.log("Result: "+initialArray[index])
return initialArray[index]
}
function compare(leftLimit, rightLimit) {
var r = (leftLimit < rightLimit ? -1 : 1)
if (r < 0) {
return true
}
else {
return false
}
}
Youare not taking in account the limits index which change and at the end you dont know if you have not more options to search or if the findTerm doesnt exits at all.
You only need to change the follow line
while (compare(leftLimit, rightLimit) && leftLimitIndex <= rightLimitIndex) {
Regards,
I create an instance of the SortableArray class
let test = new SortableArray([0, 50, 20, 10, 60, 30]);
I then call quickselect on the instance like so to find the 1st lowest value, The 1st lowest value is actually the second-lowest value since it is zero-indexed.
test.quickselect(1, 0, test.array.length - 1);
I then get undefined, which doesn't make any sense since the quickselect method contains a return statement.
class SortableArray{
constructor(array){
this.array = array;
}
swap(pointer1, pointer2){
let temporary = this.array[pointer1];
this.array[pointer1] = this.array[pointer2];
this.array[pointer2] = temporary
}
partition(leftPointer, rightPointer) {
let count = 0;
let temporary;
let pivotPosition = rightPointer;
let pivot = this.array[pivotPosition];
rightPointer -= 1;
do{
while((this.array[leftPointer] < pivot) && (leftPointer <= rightPointer)){
leftPointer++;
}
while((this.array[rightPointer] > pivot) && (leftPointer <= rightPointer)){
rightPointer--;
}
if((leftPointer <= rightPointer)){
this.swap(leftPointer,rightPointer);
continue;
}
break;
}while((leftPointer !== rightPointer) && (leftPointer <= rightPointer));
this.swap(leftPointer, pivotPosition);
return leftPointer;
}
quickselect(kthLowestValue, leftIndex, rightIndex){
debugger;
if(rightIndex - leftIndex <= 0){
return this.array[leftIndex];
}
let pivotPosition = this.partition(leftIndex, rightIndex);
if(kthLowestValue < pivotPosition){
this.quickselect(kthLowestValue, leftIndex, pivotPosition - 1);
}else if(kthLowestValue > pivotPosition){
this.quickselect(kthLowestValue, pivotPosition + 1, rightIndex);
}else{
**return this.array[pivotPosition];**
}
}
}
You need to return the values when calling quickselect in your if/else code and not only in the else like this
if (kthLowestValue < pivotPosition) {
return this.quickselect(kthLowestValue, leftIndex, pivotPosition - 1);
} else if (kthLowestValue > pivotPosition) {
return this.quickselect(kthLowestValue, pivotPosition + 1, rightIndex);
} else {
return this.array[pivotPosition];
}
This is a small mocha test file to confirm this:
import SortableArray from "./SortableArray";
describe('Check code', function () {
it('Run a test', function () {
let test = new SortableArray([0, 50, 20, 10, 60, 30]);
let x = test.quickselect(1, 0, test.array.length - 1);
console.log(x);
})
})
The result of the new code is: 10
I am trying to learn Typescript in combination with some exercises. I can't figure out why I am getting this error of too much recursion. I made some wrapper-functions.
Wrapper-functions
type Fun<a,b> = {
f: (i:a) => b
then: <c>(g:Fun<b,c>) => Fun<a,c>
}
let myFunction = function<a,b>(f:(_:a) => b) : Fun<a,b> {
return {
f:f,
then: function<c>(this:Fun<a,b>, g:Fun<b,c>) : Fun<a,c> {
return then(this,g);
}
}
};
let then = function<a,b,c>(f: Fun<a,b>, g:Fun<b,c>) : Fun<a,c> {
return myFunction(a => g.f(f.f(a)))
};
I'd like to create my own RepeatFunction so to say, whereas I can pass a function and an amount of executes as parameters.
My code
let increase = myFunction<number,number>(x => x + 1);
let RepeatFunction = function<a>(f: Fun<a,a>, n: number) : Fun<a,a> {
if (n < 0)
{
return myFunction(x => f.f(x));
}
else
{
for (let i = 0; i < n; i++)
{
RepeatFunction(myFunction<a,a>(x => this.f(x)), n); //error in console
}
}
};
console.log(RepeatFunction(increase, 2).f(10));
I'd like to call RepeatFunction, pass in my increase-function with to execute 2 times on number 10.
I am getting the error: 'Too much recursion'. Could anyone tell me what I am missing here? There are no syntax errors.
edit 2
let RepeatFunction = function<a>(f: Fun<a,a>, n: number) : Fun<a,a> {
if (n < 0)
{
return myFunction(x => f.f(x));
}
else
{
return RepeatFunction(myFunction<a,a>(x => f.f(x)), n - 1);
}
};
console.log(RepeatFunction(incr, 1).f(10)); // answer is: 11
console.log(RepeatFunction(incr, 5).f(10)); // answer is: 11
console.log(RepeatFunction(incr, 50).f(10)); // answer is: 11
The problem is that this is infinitely recursive because n never changes in value, you always call RepeatFunction with the same n. My guess is you want to call it n times, so you should decrease n next time you call it, or you can use an iterative version :
let RepeatFunction = function<a>(f: Fun<a,a>, n: number) : Fun<a,a> {
if (n < 1)
{
return myFunction(x => f.f(x));
}
else
{
var fn = myFunction<a,a>((x) => f.f(x));
for (var i = 0; i < n; i++) {
fn = fn.then(f);
}
return fn;
}
};