I have a problem I am sitting on for the past few days.
I want to write an optimal (in JS) program for verifying if a number is a Palindrome.
My current approach:
function isPalidrom2(pali){
//MOST time consuming call - I am splitting the digit into char array.
var digits = (""+pali).split("");
//To get the length of it.
var size = digits.length;
var isPali = true;
for(var i = 0; i<Math.floor(size/2); i++){
//I am comparing digits (first vs last, second vs last-1, etc.) one by one, if ANY of the pars is not correct I am breaking the loop.
if(parseInt(digits[i]) != parseInt(digits[size-i-1])){
isPali = false;
break;
}
}
return isPali;
}
It's not optimal. The biggest amount of time I am waisting is the change from INT to STRING.
And I am out of ideas
- I tried to understand the BIT operators but I can't.
- I tried to google and look for alternative approaches - but I can't find anything.
- I tried to play with different algorithms - but this one is the fastest I was able to apply.
So in short - my question is:
"how can I make it faster?"
EDIT:
So the task I want to solve:
Find all of the prime numbers within the range of all five digit numbers.
Among all of the multiplies (i*j) they are between them, find the most significant palindrome.
My current approach:
function isPrime(number){
var prime = true;
var i
for(i = 2; i<= number/2; i++){
if((number%i)==0){
prime = false;
break;
}
}
return prime;
}
function get5DigitPrimeNr(){
var a5DigitsPrime = [];
var i;
for(i = 10000; i<100000; i++){
if(isPrime(i)){
a5DigitsPrime.push(i)
}
}
return a5DigitsPrime;
}
function isPalidrom(pali){
var digits = (""+pali).split("");
//we check if first and last are the same - if true, we can progress
size = digits.length;
return
(digits[0]==digits[size-1]) &&
(parseInt(digits.slice(1, Math.floor(size/2)).join("")) ==
parseInt(digits.reverse().slice(1, Math.floor(size/2)).join("")))
}
function isPalidrom2_48s(str) {
var str = str.toString();
const lower = str.substr(0, Math.floor(str.length / 2));
const upper = str.substr(Math.ceil(str.length / 2));
return lower.split("").reverse().join("") === upper;
}
function isPalidrom_22s(pali){
var digits = (""+pali).split("");
var size = digits.length;
for(var i = 0; i<Math.floor(size/2); i++){
//console.log("I am comparing: "+i+", and "+(size-i-1)+" elements in array")
//console.log("I am comparing digit: "+digits[i]+", and "+digits[(size-i-1)]+"")
if(digits[i] !== digits[size-i-1]){
//console.log('nie sa rowne, koniec')
return false;
}
}
return true;
}
function isPalidrom2_80s(pali){
return parseInt(pali) == parseInt((""+pali).split("").reverse().join(""))
}
function runme(){
var prime5digits = get5DigitPrimeNr();
var size = prime5digits.length;
var max = 0;
var message = "";
for(var i = 0; i<size; i++){
for(var j = 0; j<size; j++){
var nr = prime5digits[i]*prime5digits[j];
if(nr>max && isPalidrom2(nr)){
max = nr;
message = 'biggest palidrome nr: '+nr+', made from numbers: '+prime5digits[i]+' x '+prime5digits[j];
}
}
}
console.log(message)
}
function timeMe(){
var t0 = performance.now();
runme();
var t1 = performance.now();
console.log("Function took " + millisToMinutesAndSeconds(t1 - t0) + " s to find the perfect palindrom.")
}
//helper functons:
function millisToMinutesAndSeconds(millis) {
var minutes = Math.floor(millis / 60000);
var seconds = ((millis % 60000) / 1000).toFixed(0);
return minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
}
To keep the spirit of you code, you could exit the loop with return instead of break and use the string directly without converting to an array. Strings have, as arrays, the possibility of an access single character with an index.
function isPalidrom2(value) {
var digits = value.toString(),
length = digits.length,
i, l;
for (i = 0, l = length >> 1; i < l; i++) {
if (digits[i] !== digits[length - i - 1]) {
return false;
}
}
return true;
}
console.log(isPalidrom2(1));
console.log(isPalidrom2(12));
console.log(isPalidrom2(1221));
console.log(isPalidrom2(123));
The fastest is probably to rely on javascripts native methods:
function isPalindrome(str) {
const lower = str.substr(0, Math.floor(str.length / 2));
const upper = str.substr(Math.ceil(str.length / 2));
return lower.split("").reverse().join("") === upper;
}
Or leave away all unneccessary conversions from your code:
function isPlaindrome(str) {
const half = str.length / 2;
for(var i = 0; i < half; i++)
if(str[i] !== str[str.length - i - 1])
return false;
return true;
}
If you're trying to speed things up, you could shave a few more seconds off by optimising your isPrime(n) function.
You don't need to check every factor, only the prime factors less than sqrt(n)
If you check every number from 2 to 99999 in ascending order, you can store the results as you go, so you don't need to keep re-calculating the list of previous primes
Something like this:
var savedPrimes = [2]
function isPrime(n){
// call this method with increasing values of n (starting at 2), saving primes as we go,
// so we can safely assume that savedPrimes contains all primes less than n
for(var i=0; i<savedPrimes.length; i++)
{
var f = savedPrimes[i];
if ((n % f) == 0)
return false; // found a factor
if (f*f>=n)
break; // stop checking after f >= sqrt(n)
}
// no prime factors - we found a new prime
savedPrimes.push(n);
return true;
}
function get5DigitPrimeNr(){
var a5DigitsPrime = [];
var i;
// first find all the primes less than 10000
for(i = 3; i<10000; i++){
isPrime(i);
}
// now find (and keep) the rest of the primes up to 99999
for(i = 10000; i<100000; i++){
if(isPrime(i)){
a5DigitsPrime.push(i)
}
}
return a5DigitsPrime;
}
EDIT - when I run your code with this method, I get a time of 10 sec
Code :
There are multiple methods that you can use (dunno if they are optimal) :
Palindrom = _ => (_=''+_) === [..._].sort(_=>1).join``
Some more :
let isPalindrome = __ => (_=(__=__+'').length)==0||_==1?!0:__[0]==__.slice(-1)?isPalindrome(__.slice(1,-1)):!1
let isPalindrome = (s,i) => (i=i||0)<0||i>=(s=''+s).length>>1||s[i]==s[s.length-1-i]&&isPalindrome(s,++i);
let isPalindrome = (str) => {
var len = ~~((str=str+'').length / 2);
for (var i = 0; i < len; i++)
if (str[i] !== str[str.length - i - 1])
return false;
return true;
}
Updated now takes numbers as input
Related
I've tried to use this code:
function calc (n, c) {
let a = 0
const omega = Math.pow(2, n)
let search1 = ''
let search2 = ''
for (let i = 0; i < c; i++) {
search1 += '0'
}
for (let i = 0; i < c; i++) {
search2 += '1'
}
for (let i = 0; i < omega; i++) {
if (i.toString(2).includes(search1) || i.toString(2).includes(search2)) {
a++
}
}
const prob = a * 100 / omega
console.log({ a: a, omega: omega, prob: prob.toFixed(2) })
}
calc(1000, 8)
Which works, but is slow when it comes to big numbers. How can I optimize my code to make it faster? Or maybe there exists a Mathematical solution, that doesn't require to code at all? I just want to know the solution for this problem.
First a Monte Carlo simulation answer:
You can find a confidence interval for this simulation by doing some statistical inference on the Bernoulli distribution which I won't do here.
function doesItHappen(l,r){
var lastValue = null;
var lastN = 0;
for(var i = 0; i < l; i++){
var currentValue = Math.random() > 0.5 ? 1 : 0;
if(lastValue === currentValue) {
lastN++;
} else {
lastValue = currentValue;
lastN = 1;
}
if(lastN === r) return true;
}
return false;
}
function rep(n,l,r){
var t = 0;
for(var i = 0; i < n; i++) {
if(doesItHappen(l,r)) t++;
}
return t/n;
}
console.log(rep(100000,1000,8))
Finally the actual Mathematical answer
I couldn't find a solution to this question online so I came up with my own method to calculate this in o(n) time and space complexity, you can even get it down to o(1) space complexity by discarding valueStore objects older than the length of consecutive sequence you want. The key thing is to recognise you have to computer all the combinations prior to the current length, similar to a Fibonacci sequence.
function calculateProbability(l,r) {
var valueStore = [
{ // Initialize it
totalNumberOfCombinations: 2,
numberOfCombinationsWithSequence: 0
}
];
function getValues(index) {
// combinations with the sequence in it
// There are two ways a consecutive sequence of r length can occur, it either occured in the previous combination and we flipped a new heads or tails(doesn't matter)
// Or this flip resulted in a new consecutive sequence of r length occuring (let's say theres k combinations of this)
// Heres the genius, k must end in a sequence of heads or tails so theres 2 possible endings, the beginnings of k cannot contain the sequence of r consecutive flips
// If this previous combination ends in a head then the new sequence is all tails and vice versa
// So k = the combinations of flips without the consective flips before the current sequence
// k = the totalNumberOfCombinations 8 flips ago - numberOfCombinationsWithSequence 8 flips ago
if (index === r - 1) {
// All heads or all tails
var numberOfCombinationsWithSequence = 2;
} else if(index < r) {
var numberOfCombinationsWithSequence = 0;
} else {
var numberOfCombinationsWithSequence = valueStore[index - 1].numberOfCombinationsWithSequence * 2 + (valueStore[index - r].totalNumberOfCombinations - valueStore[index - r].numberOfCombinationsWithSequence)
}
return {
// total possible combinations
// this is just the previous number of combinations but times 2 since we flip again
totalNumberOfCombinations: valueStore[index - 1].totalNumberOfCombinations * 2,
numberOfCombinationsWithSequence: numberOfCombinationsWithSequence
}
}
for(var i = 1; i < l; i++) {
var values = getValues(i);
valueStore.push(values);
}
return valueStore[valueStore.length - 1].numberOfCombinationsWithSequence / valueStore[valueStore.length - 1].totalNumberOfCombinations;
}
console.log(calculateProbability(1000,8));
The 100% accurate answer is 0.9817098435878764 or 98.17%
how about a simulation?
function simulate(throws, streak, runs) {
let win = "".padStart(streak, "1")
let win2 = "".padStart(streak, "0")
let hits = 0
for (let n = 0; n < runs; n++) {
let res = "";
for (let i = 0; i < throws; i++) {
let val = Math.round(Math.random())
res += val
}
if (res.includes(win) || res.includes(win2)) {
hits++
}
}
console.log({
hits,
runs,
prob: ((hits / runs) * 100).toFixed(2)
})
}
simulate(1000, 8, 10000)
I'm taking a course on FreeCodeCamp.org and the assignment is to find "Smallest Common Multiple". So I came up with a solution I think works and I does up to a certain point. Then the code just seems like it's breaking down. Here is my code:
function smallestCommons(arr) {
arr = arr.sort((a,b) => {return a - b;});
console.log(arr);
var truesec = false;
for(var a = arr[1]; truesec != true; a++){
for(var e = 1; e <= arr[1]; e++){
//console.log(a % e + " " + e);
if(a % e != 0){
truesec = false;
break;
}else{
truesec = true;
}
}
//console.log(truesec + " " + a);
if(truesec == true){
return a;
}
}
return a;
}
console.log(smallestCommons([23,18]));
This should return 6056820 according to their checklist but every time I check I get a different result I've gotten both 114461 & 122841 from the same code. Can somebody please tell me what is wrong with this?
Here is the assignment if it helps:
Intermediate Algorithm Scripting: Smallest Common Multiple
What your algorithm trying to do is find the common multiple between 1 and the greater number in the array, which might take a very long time. However, the question from the FreeCodeCamp asks you to find the common multiple between the two numbers in the array, so the result calculated from your algorithm does not match the tests.
To make your solution works, you can change
from for (var e = 1; e <= arr[1]; e++)
to for (var e = arr[0]; e <= arr[1]; e++)
in order to loop between two numbers in the array.
I would take a different approach to this problem:
create function to get all prime factors
create array of prime factor of all number between a[0] and a[1]
reduce the array as the biggest power for each prime factor.
multiple all the prime factor left in the array
Your approach will take O(k*a[1]) when k is the answer - and k can be very high... This approach will take O((a[1])^2)
Consider the following code:
function smallestCommons2(arr) {
arr.sort((a,b) => {return a - b;});
let factors = [];
for(let i = arr[0]; i <= arr[1]; i++)
factors.push(findPrimeFactors(i));
let reduced = reduceFactors(factors);
let ans = 1;
for (let i in reduced)
ans *= Math.pow(i, reduced[i]);
return ans;
}
function reduceFactors(factorsArr) {
let factorObject = {};
for (let i in factorsArr) {
for(let key in factorsArr[i]) {
if (!(key in factorObject) || factorObject[key] < factorsArr[i][key])
factorObject[key] = factorsArr[i][key];
}
}
return factorObject;
}
function findPrimeFactors (num) {
var primeFactors = [];
while (num % 2 === 0) {
primeFactors.push(2);
num = num / 2;
}
var sqrtNum = Math.sqrt(num);
for (var i = 3; i <= sqrtNum; i++) {
while (num % i === 0) {
primeFactors.push(i);
num = num / i;
}
}
if (num > 2)
primeFactors.push(num);
let factorObject = {};
for (let item of primeFactors) {
if (item in factorObject)
factorObject[item] += 1;
else factorObject[item] = 1;
}
return factorObject;
}
console.log(smallestCommons2([23,18]));
This code will output 6056820 in sec
Edited - found a post that do the same thing in a better way
I have solved the seventh problem of Euler, it says:
By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can
see that the 6th prime is 13.
What is the 10 001st prime number?
I solved it using, and in the array in which I keep the cousins, when it reaches the length of 10001, I return that number. The algorithm takes 1300 ms, which I tink that is very inefficient, what am I doing particularly in my implementation?
var start = performance.now();
function eratosthenes(n) {
var arr = [2], acc = 0;
// matrix to save the found prime numbers and mark their multiples
for(var i = 3; true; i += 2) { // loop
if(arr.length === n) return arr[arr.length - 1]; // if the array length is equal to n return the last number
if(!resolve(arr, i)) { // check if is multiple of the prime numbers, already found.
arr.push(i); // if isnt multiple, save it
}
}
}
function resolve(array, n) {
return array.some(cur => !(n%cur));
}
console.log(eratosthenes(10001)); // Tooks 1300 ms
var end = performance.now();
var time = end - start;
console.log(time);
Euler sieve, Pham knows this one :) 12ms
Uchu, I don't see where your code is marking the multiples. Isn't that what Sieve of Eratosthenes is supposed to do?
JavaScript code (this code is actually an adaptation of code by btilly, optimizing an idea of mine):
var start = performance.now();
n = 115000
a = new Array(n+1)
total = 0
s = []
p = 1
count = 0
while (p < n){
p = p + 1
if (!a[p]){
count = count + 1
if (count == 10001){
console.log(p);
end = performance.now();
time = end - start;
console.log(time);
break;
}
a[p] = true
s.push(p)
limit = n / p
new_s = []
for (i of s){
j = i
while (j <= limit){
new_s.push(j)
a[j*p] = true;
j = j * p
}
}
s = new_s
}
}
As requested by JaromandaX, this is the code for Sieve of Eratosthenes. 51 ms on my browser (OP solution is 750 ms)
var max = 1000000;
function eratosthenes(n) {
var arr = [], count = 0;
for (var i = 0; i < max; i++){
arr.push(true);
}
for (var i = 2; i < max; i++){
if(arr[i]){
count++;
if(count == n){
return i;
}
for (var j = i + i; j < max; j += i ){
arr[j] = false;
}
}
}
}
var start = performance.now();
console.log(eratosthenes(10001));
var end = performance.now();
var time = end - start;
console.log(time);
This has a similar running time to גלעד ברקן's answer (actually about 10% faster on my machine), but doesn't rely on knowing an approximate max before starting. It performs a seive of Eratosthenes up to max (starting at 2) and then doubles max, initialises the new elements in the array per the previously found primes and repeats.
function eratosthenes(n) {
let prev_max = 1, max = 2, i, j;
const primes = [], is_prime = new Array(max+1).fill(true);
while( true ) {
for ( i = prev_max + 1; i <= max; i++){
if ( ! is_prime[i] ) continue;
primes.push( i );
if ( primes.length === n )
return i;
for ( j = i + i; j <= max; j += i )
is_prime[j] = false;
}
const next_max = max*2;
is_prime.length = next_max + 1;
is_prime.fill( true, max + 1, next_max );
for ( i = 0; i < primes.length; i++ ) {
const prime = primes[i];
for ( j = max + prime - max%prime; j <= next_max; j += prime )
is_prime[j] = false;
}
prev_max = max;
max = next_max;
}
}
var start = performance.now();
console.log(eratosthenes(10001));
var end = performance.now();
var time = end - start;
console.log(time);
If it is a code-writing exercise, it is better to explore the earlier answers.
But if you are after a simple and fast solution, here's how you can solve it using prime-lib, which I created:
import {generatePrimes} from 'prime-lib';
const seekIndex = 10_001; // index of the prime being sought
const start = Date.now();
let a, c = 0;
const i = generatePrimes({boost: seekIndex + 1});
while ((a = i.next()) && !a.done && c++ < seekIndex) ;
console.log(`Prime: ${a.value}, took ${Date.now() - start}ms`);
On my PC it spits out:
Prime: 104759, took 5ms
And with the modern RXJS this becomes even simpler still:
import {generatePrimes} from 'prime-lib';
import {from, last} from 'rxjs';
const seekIndex = 10_001; // index of the prime being sought
const i = generatePrimes({boost: seekIndex + 1});
from(i).pipe(last()).subscribe(console.log);
//=> 104759
I am new to Javascript, I am doing a coding challenge to learn more about the language. This is not school related or anything like that, totally for my own personal growth. Here is the challenge:
Return the sum of all odd Fibonacci numbers up to and including the
passed number if it is a Fibonacci number.
I have spent the past 2 evenings working on solving this challenge. When I run my code using underscore.js it works. When I use Ramda.js it says NaN. I would think both would return NaN. I'm very surprised that I can get the correct answer from one and not the other. Any insights would be greatly appreciated!
var R = require('ramda');
function sumFibs(num) {
var fib_Arr = [];
var new_Arr = [];
var total = 0;
// I use this to tell if the fib num is greater than 2
var the_Bit = "false";
// This is used to keep track of when to stop the loop
var fib_Num = 0;
// THIS WORKS FROM HERE
// This loop generates a list of fibonacci numbers then pushes them to the fib_Arr
for(var i = 0; total < num; i++){
if (i < 1){
fib_Arr.push(0);
}
else if (i === 1){
fib_Arr.push(i);
fib_Arr.push(1);
}
else if (i === 2){
fib_Arr.push(2);
the_Bit = "true";
}
else if (the_Bit === "true"){
temp_Arr = R.last(fib_Arr,2);
temp_Arr = temp_Arr[0] + temp_Arr[1];
fib_Arr.push(temp_Arr);
total = R.last(fib_Arr);
}
// Generating the fib Array works TO HERE!!!!
}
// console.log(fib_Arr); // Print out the generated fibonacci array
// if last Array element is greater than the original in
var last_Element = R.last(fib_Arr);
if (last_Element > num){
console.log("The last element of the array is bigger!");
fib_Arr.splice(-1,1); // This removes the last item from the array if it is larger than the original num input
}
// This loop removes all of the EVEN fibonacci numbers and leaves all of the ODD numbers
for (var j = 0; j < fib_Arr.length; j++){
if (fib_Arr[j] % 2 !== 0){
new_Arr.push((fib_Arr[j]));
}
}
// This checks if the original input num was a
if (num % 2 !== 0){
new_Arr.push(num);
}
else{
console.log("The original num was not a Fibonacci number!");
}
// if last Array element is the same as the original input num
var last = R.last(fib_Arr);
if (last === num){
console.log("Removing the last element of the array!");
new_Arr.splice(-1,1); // This removes the last item from the array if it is the same as the original num input
}
// Now to add all of the numbers up :-)
for (var k = 0; k < new_Arr.length; k++){
console.log("This is fib_Num: " + fib_Num);
// console.log(fib_N`);
fib_Num = fib_Num += new_Arr[k];
}
return fib_Num;
}
// TEST CASES:
// console.log(sumFibs(75025)); //.to.equal(135721);
console.log(sumFibs(75024)); //.to.equal(60696);
You have a problem on these lines :
temp_Arr = R.last(fib_Arr,2);
temp_Arr = temp_Arr[0] + temp_Arr[1];
Besides the fact that R.last does not take a second argument (that will not fail though), you are using temp_arr as an array, when it is a number. Therefore, temp_arr gets a NaN value.
You are probably looking for R.take (combined with R.reverse) or R.slice.
By changing :
temp_Arr = R.last(fib_Arr,2);
with :
temp_Arr = R.take(2, R.reverse(fib_Arr));
or with :
temp_Arr = R.slice(fib_Arr.length - 2, fib_Arr.length)(fib_Arr);
or with (bonus play with a reduce from the right) :
temp_Arr = R.reduceRight(function(arr, elem) {
return arr.length < 2 ? [elem].concat(arr) : arr;
}, [])(fib_Arr);
We get :
sumFibs(75024) === 60696
For the record, here's how you do this problem:
function fibSumTo(n) {
var f1 = 1, f2 = 1, sum = 1, t;
while (f2 <= n) {
if (f2 & 1) sum += f2;
t = f1 + f2;
f1 = f2;
f2 = t;
}
return sum;
}
There's really no need for any sort of library because there's really no need for any sort of data structure.
var _ = require('underscore');function sumUpFibs (number){
arr_of_fibs = [1,1];
current = 1; //cursor for previous location
while (true){
var num = arr_of_fibs[current] + arr_of_fibs[current - 1];
if (num <= number) {
arr_of_fibs.push(num);
current++;
} else {
break;
}
}
console.log(arr_of_fibs);
var total = 0;
_.each(arr_of_fibs, function(fib){
total += fib;
})
return total;}console.log(sumUpFibs(75025));
This may be a better implementation... Though I know you're just starting so I don't want to come off as mean : D.... Also, maybe check your test cases too.
I am just starting JS, and understand the concept of finding a factor. However, this snippet of code is what I have so far. I have the str variable that outputs nothing but the first factor which is 2. I am trying to add each (int) to the str as a list of factors. What's the wrong in below code snippet?
function calculate(num) {
var str = "";
var int = 2;
if (num % int == 0) {
str = str + int;
int++;
} else {
int++;
}
alert(str);
}
calculate(232);
UPDATED ES6 version:
As #gengns suggested in the comments a simpler way to generate the array would be to use the spread operator and the keys method:
const factors = number => [...Array(number + 1).keys()].filter(i=>number % i === 0);
console.log(factors(36)); // [1, 2, 3, 4, 6, 9, 12, 18, 36]
ES6 version:
const factors = number => Array
.from(Array(number + 1), (_, i) => i)
.filter(i => number % i === 0)
console.log(factors(36)); // [1, 2, 3, 4, 6, 9, 12, 18, 36]
https://jsfiddle.net/1bkpq17b/
Array(number) creates an empty array of [number] places
Array.from(arr, (_, i) => i) populates the empty array with values according to position [0,1,2,3,4,5,6,7,8,9]
.filter(i => ...) filters the populated [0,1,2,3,4,5] array to the elements which satisfy the condition of number % i === 0 which leaves only the numbers that are the factors of the original number.
Note that you can go just until Math.floor(number/2) for efficiency purposes if you deal with big numbers (or small).
As an even more performant complement to #the-quodesmith's answer, once you have a factor, you know immediately what its pairing product is:
function getFactors(num) {
const isEven = num % 2 === 0;
const max = Math.sqrt(num);
const inc = isEven ? 1 : 2;
let factors = [1, num];
for (let curFactor = isEven ? 2 : 3; curFactor <= max; curFactor += inc) {
if (num % curFactor !== 0) continue;
factors.push(curFactor);
let compliment = num / curFactor;
if (compliment !== curFactor) factors.push(compliment);
}
return factors;
}
for getFactors(300) this will run the loop only 15 times, as opposed to +-150 for the original.
#Moob's answer is correct. You must use a loop. However, you can speed up the process by determining if each number is even or odd. Odd numbers don't need to be checked against every number like evens do. Odd numbers can be checked against every-other number. Also, we don't need to check past half the given number as nothing above half will work. Excluding 0 and starting with 1:
function calculate(num) {
var half = Math.floor(num / 2), // Ensures a whole number <= num.
str = '1', // 1 will be a part of every solution.
i, j;
// Determine our increment value for the loop and starting point.
num % 2 === 0 ? (i = 2, j = 1) : (i = 3, j = 2);
for (i; i <= half; i += j) {
num % i === 0 ? str += ',' + i : false;
}
str += ',' + num; // Always include the original number.
console.log(str);
}
calculate(232);
http://jsfiddle.net/r8wh715t/
While I understand in your particular case (calculating 232) computation speed isn't a factor (<-- no pun intended), it could be an issue for larger numbers or multiple calculations. I was working on Project Euler problem #12 where I needed this type of function and computation speed was crucial.
function calculate(num) {
var str = "0";
for (var i = 1; i <= num; i++) {
if (num % i == 0) {
str += ',' + i;
}
}
alert(str);
}
calculate(232);
http://jsfiddle.net/67qmt/
Below is an implementation with the time complexity O(sqrt(N)):
function(A) {
var output = [];
for (var i=1; i <= Math.sqrt(A); i++) {
if (A % i === 0) {
output.push(i);
if (i !== Math.sqrt(A)) output.push(A/i);
}
}
if (output.indexOf(A) === -1) output.push(A);
return output;
}
here is a performance friendly version with complexity O(sqrt(N)).
Output is a sorted array without using sort.
var factors = (num) => {
let fac = [], i = 1, ind = 0;
while (i <= Math.floor(Math.sqrt(num))) {
//inserting new elements in the middle using splice
if (num%i === 0) {
fac.splice(ind,0,i);
if (i != num/i) {
fac.splice(-ind,0,num/i);
}
ind++;
}
i++;
}
//swapping first and last elements
let temp = fac[fac.length - 1];
fac[fac.length - 1] = fac[0];
fac[0] = temp;
// nice sorted array of factors
return fac;
};
console.log(factors(100));
Output:
[ 1, 2, 4, 5, 10, 20, 25, 50, 100 ]
This got me an 85% on Codility (Fails on the upperlimit, over a billion).
Reducing the input by half doesn't work well on large numbers as half is still a very large loop. So I used an object to keep track of the number and it's half value, meaning that we can reduce the loop to one quarter as we work from both ends simultaneously.
N=24 becomes: (1&24),(2&12),(3&8),(4&6)
function solution(N) {
const factors = {};
let num = 1;
let finished = false;
while(!finished)
{
if(factors[num] !== undefined)
{
finished = true;
}
else if(Number.isInteger(N/num))
{
factors[num] = 0;
factors[N/num]= 0;
}
num++
}
return Object.keys(factors).length;
}
Using generators in typescript in 2021
function* numberFactorGenerator(number: number): Generator<number> {
let i: number = 0;
while (i <= number) {
if (number % i === 0) {
yield i;
}
i++;
}
}
console.log([...numberFactorGenerator(12)]); // [ 1, 2, 3, 4, 6, 12 ]
function factorialize(num) {
var result = '';
if( num === 0){
return 1;
}else{
var myNum = [];
for(i = 1; i <= num; i++){
myNum.push(i);
result = myNum.reduce(function(pre,cur){
return pre * cur;
});
}
return result;
}
}
factorialize(9);
I came looking for an algorithm for this for use in factoring quadratic equations, meaning I need to consider both positive and negative numbers and factors. The below function does that and returns a list of factor pairs. Fiddle.
function getFactors(n) {
if (n === 0) {return "∞";} // Deal with 0
if (n % 1 !== 0) {return "The input must be an integer.";} // Deal with non-integers
// Check only up to the square root of the absolute value of n
// All factors above that will pair with factors below that
var absval_of_n = Math.abs(n),
sqrt_of_n = Math.sqrt(absval_of_n),
numbers_to_check = [];
for (var i=1; i <= sqrt_of_n; i++) {
numbers_to_check.push(i);
}
// Create an array of factor pairs
var factors = [];
for (var i=0; i <= numbers_to_check.length; i++) {
if (absval_of_n % i === 0) {
// Include both positive and negative factors
if (n>0) {
factors.push([i, absval_of_n/i]);
factors.push([-i, -absval_of_n/i]);
} else {
factors.push([-i, absval_of_n/i]);
factors.push([i, -absval_of_n/i]);
}
}
}
// Test for the console
console.log("FACTORS OF "+n+":\n"+
"There are "+factors.length+" factor pairs.");
for (var i=0; i<factors.length; i++) {
console.log(factors[i]);
}
return factors;
}
getFactors(-26);
function calculate(num){
var str = "0" // initializes a place holder for var str
for(i=2;i<num;i++){
var num2 = num%i;
if(num2 ==0){
str = str +i; // this line joins the factors to the var str
}
}
str1 = str.substr(1) //This removes the initial --var str = "0" at line 2
console.log(str1)
}
calculate(232);
//Output 2482958116
Here's an optimized solution using best practices, proper code style/readability, and returns the results in an ordered array.
function getFactors(num) {
const maxFactorNum = Math.floor(Math.sqrt(num));
const factorArr = [];
let count = 0; //count of factors found < maxFactorNum.
for (let i = 1; i <= maxFactorNum; i++) {
//inserting new elements in the middle using splice
if (num % i === 0) {
factorArr.splice(count, 0, i);
let otherFactor = num / i; //the other factor
if (i != otherFactor) {
//insert these factors in the front of the array
factorArr.splice(-count, 0, otherFactor);
}
count++;
}
}
//swapping first and last elements
let lastIndex = factorArr.length - 1;
let temp = factorArr[lastIndex];
factorArr[lastIndex] = factorArr[0];
factorArr[0] = temp;
return factorArr;
}
console.log(getFactors(100));
console.log(getFactors(240));
console.log(getFactors(600851475143)); //large number used in Project Euler.
I based my answer on the answer written by #Harman
We don't have to loop till end of the given number to find out all the factors. We just have to loop till reaching the given number's squareroot. After that point we, can figure out the rest of the factors by dividing the given number with the already found factors.
There is one special case with this logic. When the given number has a perfect square, then the middle factor is duplicated. The special case is also handled properly in the below code.
const findFactors = function (num) {
const startingFactors = []
const latterFactors = []
const sqrt = Math.sqrt(num)
for (let i = 1; i <= sqrt; i++) {
if (num % i == 0) {
startingFactors.push(i)
latterFactors.push(num / i)
}
}
// edge case (if number has perfect square, then the middle factor is replicated, so remove it)
if (sqrt % 1 == 0) startingFactors.pop()
return startingFactors.concat(latterFactors.reverse())
}
function factorialize(num) {
if(num === 0)
return 1;
var arr = [];
for(var i=1; i<= num; i++){
arr.push(i);
}
num = arr.reduce(function(preVal, curVal){
return preVal * curVal;
});
return num;
}
factorialize(5);