JavaScript - Large Index Values Lead to Infinite Loops - Not Sure Why? - javascript

I'm working on a Project Euler problem (#3) - Largest Prime Factor.
The code I have written seems to work for smaller numbers but not for bigger numbers (see 2nd invocation of the function). If I try that, it goes into an infinite loop and I can't figure out why. I've tried JSBin to test and it does the same thing ('potential infinite loop') so I have no idea how to debug this issue.
Would appreciate help with this.
Here's my code:
//Prime Checker
var isPrime = function (num) {
for(var i = 2; i < num; i++) {
if(num % i === 0) {
return false;
}
}
return true;
}; //end function
//Largest Prime Factor
var primeFactor = function (num) {
var result = 0;
var temp = 0;
var primeArr = [];
for (var i = 2; i <= num; i++) {
if (num % i === 0) {
temp = i;
if (isPrime(temp)) {
primeArr.push(temp);
}
}
}
console.log("primeArr: " + primeArr);
//sort
primeArr.sort(function(a,b) {
return b - a;
});
result = parseInt(primeArr[0]);
console.log("result: " + result);
return result;
}; //end function
primeFactor(13195); //WORKS FINE
primeFactor(600851475143); //CAUSES INFINITE LOOP

As mentioned in one of the comments, if JavaScript runs out of memory in a math equation it can sometimes lead to infinite loops through things such as memory links. If you need a solution, there are some JavaScript libraries such as big.js that handle large math equations, however I don't know if it will be able to help this. The only way to find out is to try. Hope this helps.

Related

Why is my function working when called by itself but not when I call it with another function? (Beginner javascript question)

I am working on some coding challenges (I am still a beginner). I was able to make both of these functions work, but when I try to call them together my second function just returns zero..
Both functions take in two parameters (or more). The first function counts the numbers between the two paramters and returns them in a string (1, 5) => [1,2,3,4,5] and the second sums them together (1,10) => 55. Any reason why these work individually but not together?
Thanks in advance!
`let range = (start, end) => {
numbers = [];
for(i = start; i<end+1; i++) {
if(i>=start){
numbers.push(i);
if (i>=end) {
console.log(numbers);
}
}
}
}
function sum(start, ...add){
let sumCounter = 0;
for(i = start; i<=add; i++) {
sumCounter += i;
}
return sumCounter;
}
console.log(sum(1,10)); //second function works
console.log(sum(range(1, 10))); //first function works, not second function `
There are a lot of things going on here. First make sure that you’re returning a value in the first function, and not just printing to the console. Second, when you say “if(i>=end)” that will always be true, so it isn’t needed. Also instead of saying “if(I>=end)” you can put “I==end” or just put the following code after the for loop. I would suggest that you return the numbers, and take that as a parameter for your sum function. I hope you’re able to follow all of that!
Here is a working option:
function range(start, end) {
var numbers = [];
for (i=start;i<end+1;i++) {
numbers.push(i)
}
return numbers;
}
console.log("Sum: " + range(5, 10).reduce((a,b) => a + b, 0));
Or this might be easier to understand:
function range(start, end) {
var numbers = [];
for (i=start;i<end+1;i++) {
numbers.push(i)
}
return numbers;
}
function sum(nums) {
var sum = 0;
for (i=0;i<nums.length;i++) {
sum += nums[i];
}
return sum;
}
console.log("Sum: " + sum(range(5, 10)));

Finding total number of maximum number in array fail only for big data

I doing some Hackerrank challange to improve my problem solving skills, so one of the challanges was about finding the total maximum numbers from an array of numbers. For example if we have 3 2 1 3 1 3 it should return 3
This is what I did :
function birthdayCakeCandles(ar) {
let total= 0
let sortedArray = ar.sort((cur,next)=>{
return cur<next
})
ar.map(item => {
if(item===sortedArray[0]) {
total ++;
}
})
return total
}
So I sorted the given array and then map through the array and check how many of the numbers are equal to the maximum number in that array and count the total.
This will pass 8/9 test cases, one of the test cases, have a array with length of 100000 and for this one it failed, this is the given data for this test case.
Really can't get it why it fails in this test, is it possible that this happened because of JavaScript which is always synchronous and single-threaded?
I tried to use Promise and async await, but hackerrank will consider the first return as the output ( Which is the Promise itself ) and it not use the resolve value as a output, so can't really test this.
Is it something wrong with my logic?
The sorting approach is too slow (O(n log n) time complexity). For algorithmic challenges on HR, it's unlikely that features somewhat particular to your language choice like promises/async are going to rescue you.
You can do this in one pass using an object to keep track of how many times you've "seen" each number and the array's maximum number, then simply index into the object to get your answer:
function birthdayCakeCandles(ar) {
let best = -Infinity;
const seen = {};
for (let i = 0; i < ar.length; i++) {
if (ar[i] > best) {
best = ar[i];
}
seen[ar[i]] = ++seen[ar[i]] || 1;
}
return seen[best];
}
Time and space complexity: O(n).
Edit:
This answer is even better, with constant space (here it is in JS):
function birthdayCakeCandles(ar) {
let best = -Infinity;
let count = 0;
for (const n of ar) {
if (n > best) {
best = n;
count = 1;
}
else if (n === best) {
count++;
}
}
return count;
}
In your case, the build in function sort is using the resource heavily. Maybe that's the reason it is failing for a space/time complexity.
BTW, This problem can be solved easily using a for loop. The idea is
Pseudocode
var maxNum = -999999; // put here the highest limit of int or what ever data type
int count = 0;
for(x in arr)
{
if (x > maxNum)
{
maxNum = x;
count = 1;
}
if(x==maxNum) count ++;
}
Here count will be the output.
The full code is
function birthdayCakeCandles(ar) {
var maxNum = -1;
var count = 0;
for(var i=0; i< ar.length; i++){
var x = ar[i];
if(x<maxNum) continue;
if(x>maxNum){
maxNum = x;
count = 1;
}
else{
count++;
}
}
return count;
}

Algorithm: Factorialize a Number Douts

I'm doing the factorialize algorithm challenge on FCC and I would really appreciate if someone with a greater knowledge than me would explain me what's wrong in the thinking process of my code
Im following these steps to factorialize a number:
Create a function with a parameter (num).
I create an if statement to accomplish the next task: factorialize(0) should return 1. If (num === 0) {return 1;}
Create an array inside the function.
Create a loop to iterate through num-1 numbers and push them into the array. So we add the current number + all the previous values to the array. Example: If our number is 5 we add 5, 4, 3, 2, 1.
Use the reduce method into the array to multiply the values of each number in the array (factorialize).
Return the given value.
My code:
function factorialize(num) {
if (num === 0) { return 1; }
else {var array = [];
for(i = num; i >= 1; i--){
var newArray = array.push[i];
newArray.reduce(function(previousVal, currentVal){
return previousVal * currentVal;
});
}
}
}
factorialize(5);
I am mainly getting 2 douts now. This way to solve the algorithm might not be the most efficient one okay but:
Is this a viable way to solve it?
Why am I getting "cannot read property 'reduce' of undefined".
Link to the challenge:
https://www.freecodecamp.org/challenges/factorialize-a-number
You can simply try this:
function factorialize(num) {
if (num === 0) { return 1; }
else {
for (var i = num - 1; i >= 1; i--) {
num *= i;
}
return num;
}
}
factorialize(5);

How do I optimise this javascript function for speed?

I just took the Codility tape equilibrium test here
As you can see from my score I didn't get good enough on how fast the function executes. Can anybody give me some pointers so I can optimise this code and get closer to 100%?
Here is the code...
function solution(A) {
var minimumAbsDiff = null;
for(var currentIndex =1;currentIndex < A.length;currentIndex ++){
var bottomHalf = getTotal(0,currentIndex-1,A);
var topHalf = getTotal(currentIndex,A.length-1,A);
var absDiff = Math.abs(bottomHalf - topHalf);
if(minimumAbsDiff == null){
minimumAbsDiff = absDiff;
}else{
if(absDiff < minimumAbsDiff) minimumAbsDiff = absDiff;
}
}
return minimumAbsDiff;
}
function getTotal(start,end,arrayTocheck){
var total = 0;
for(var currentIndex = start;currentIndex <= end;currentIndex++){
total = total + arrayTocheck[currentIndex];
}
return total;
}
You don't want to optimise speed. You want to lower the algorithmic complexity. Your current algorithm is O(n²), while the taks description explicitly stated that
expected worst-case time complexity is O(N);
expected worst-case space complexity is O(N), beyond input storage
(not counting the storage required for input arguments).
So what's the insight to make that possible? Each total difference is only a small distance from the others for P. If you compare the value |(A[0] + ... + A[P-1]) - (A[P] + ... + A[N-1])| for P and P+1, there is only a constant amount of work difference to be done.
function solution(A) {
var left = 0,
right = A.reduce(function(a, b) { return a + b; }, 0);
var min = Infinity;
for (var p = 0; p<A.length-1; p++) {
left += A[p];
right -= A[p];
min = Math.min(min, Math.abs(left - right));
}
return min;
}

JS crashes sometimes with Timer scramble

My Javascript timer is for people with a rubiks cube with generates a scramble (nevermind all this, but just to tell you I'm generating after each solve a new scramble will be generated) and my scrambles do actually have a while (true) statement. So that does crash my script, but it 95/100 times stops just before the script crashes but I don't wanna have any times.
Let me explain a bit more detailed about the problem.
Problem: javascript crashes because my script takes too long to generate a scramble.
Below you have 3 functions I use.
This function generates a scramble with the Fisher-Yates shuffle.
Timer.prototype.generateScramble = function(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
};
This function validates the input e.g. I receive an array as the following:
Here I only have to check the first character. That's why I use the seconds [ ] notation. I don't want people get an F with an F2 e.g.
var scr = ["F","R","U","B","L","D","F2","R2","U2","B2","L2","D2","F'","R'","U'","B'","L'","D'"]
Timer.prototype.validateScramble2 = function(array) {
var last = array.length-1;
for (var i = 0; i < array.length-1; i++) {
if (array[i][0] == array[i+1][0]) {
return false;
}
}
for (var i = 0; i < array.length-2; i++) {
if (array[i][0] == array[i+2][0]) {
return false;
}
}
if (array[0][0] == [last][0]) {
return false;
}
return true;
};
The above functions are just waiting to be called. Well in the function below I use them.
Timer.prototype.updateScramble2 = function(scrambleArr, len, type) {
var self = this;
var scramble = '', j, updatedArr = [];
while (updatedArr.length < len) {
j = (Math.floor(Math.random() * scrambleArr.length));
updatedArr.push(scrambleArr[j]);
}
while (!self.validateScramble2(updatedArr)) {
updatedArr = self.generateScramble(updatedArr);
}
for (var i = 0; i < updatedArr.length; i++) {
scramble += updatedArr[i] + ' ';
}
scrambleDiv.innerHTML = scramble;
};
I assume you guys understand it but let me explain it briefly.
The first while-loop adds a random value from the given array(scrambleArr) into a new array called updatedArr.
The next while-loop calls the validateScramble2() function if there isn't in an array F next to an F2.
The for-loop adds them into a new variable added with a whitespace and then later we show the scramble in the div: scrambleDiv.innerHTML = scramble;
What do I need know after all this information?
Well I wanna know why my updateScramble2() functions lets my browser crash every time and what I do wrong and how I should do it.
I'm not entirely sure I understand the question, but from the way your code looks, I think you have an infinite loop going on. It appears as if validateScramble2 always returns false which causes your second loop in updateScramble2 to perpetually run.
I suggest you insert a breakpoint in your code and inspect the values. You could also insert debugger; statements in your code, works the same way. Open dev tools prior to doing these.
A suggestion is instead of using loops, use a timer. This breaks up your loop into asynchronous iterations rather than synchronous. This allows the browser breathing space for other operations. Here's an example of a forEachAsync:
function forEachAsync(array, callback){
var i = 0;
var timer = setInterval(function(){
callback.call(null, array[i]);
if(++i >= array.length) clearInterval(timer);
}, 0);
}
forEachAsync([1,2,4], function(item){
console.log(item);
});
You can take this further and use Promises instead of callbacks.

Categories