Factorial in JS at my interview at Sina Weibo - javascript

how much 0 at the end of 1*2*3*....*100?
for example1 zero 10,2 zero at the end of 10100,0 zero at 10001
The interviewer gave me 3 mins.
front-end develope intern was the job i went for.
i tried to solve it in JavaScript,it was wrong because 100! is so big for a JS variable.Here is my code.
var factorial = function(x){
if(x<0){
return error;
}else if (x ===1 || x ===0) {
return x;
}else if (x > 1) {
return (factorial(x - 1) * x);
}
}
var counter = 0;
var countZero = function(x){
while((x%10) === 0){
counter = counter + 1;
x = x/10;
}
return counter;
}
console.log(countZero(factorial(100)));
Any ideas?I solved it without computer in a pure-math way,but i want to know how to solve it in JS.

A number gets a zero at the end of it if the number has 10 as a factor. For instance, 10 is a factor of 50, 120, and 1234567890. So you need to find out how many times 10 is a factor in the expansion of 100!.
But since 5×2 = 10, we need to account for all the products of 5 and 2. Looking at the factors in the above expansion, there are many more numbers that are multiples of 2 (2, 4, 6, 8, 10, 12, 14,...) than are multiples of 5 (5, 10, 15,...). That is, if we take all the numbers with 5 as a factor, We'll have way more than enough even numbers to pair with them to get factors of 10 (and another trailing zero on my factorial). So to find the number of times 10 is a factor, all we really need to worry about is how many times 5 is a factor in all of the numbers between 1 and 100
Okay, how many multiples of 5 are there in the numbers from 1 to 100? There's 5, 10, 15, 20, 25,...
Let's do this the short way: 100 is the closest multiple of 5 below or equal to 100, and 100 ÷ 5 = 20, so there are twenty multiples of 5 between 1 and 100.
But wait: 25 is 5×5, so each multiple of 25 has an extra factor of 5 that we need to account for. How many multiples of 25 are between 1 and 100? Since 100 ÷ 25 = 4, there are four multiples of 25 between 1 and 100.
Adding these, We get 20 + 4 = 24 trailing zeroes in 100!
It was more of a math question that a Javascript specific question and you don't need to calculate the actual factorial to find the number of trailing zeros
More details here

Zeros at the end of a number result from 2s and 5s being multiplied together. So, one way to count up the total number of zeros would be to figure out how many total 2s and 5s go into 100! - don't calculate that number, just add up the number of factors - and then return whichever count (2s or 5s) is smallest.
let twos = 0;
let fives = 0;
for (let i = 1; i <= 100; i++) {
let num = i;
while (num % 2 === 0) {
twos++;
num /= 2;
}
while (num % 5 === 0) {
fives++;
num /= 5;
}
}
console.log(Math.min(twos, fives));

For the numbers less or equal than 1000000000 as your case here you could use the following algorithm :
function numberOfZeros(n) {
if (n == 0) return 0;
return parseInt(n * (n - 1) / (4 * n));
}
console.log(numberOfZeros(100));

Related

Efficient way to solve "CountFactors" codility question

I have been running through Codility questions and and one of the questions was to count all the possible factors of a number. I looped through the whole number got the answer but it wasn't efficient of course.
I searched for the answer and got this
function solution(N) {
var i;
var NumFactors = 0;
for(i = 1;i*i < N; i++) {
if(N%i == 0) NumFactors += 2;
}
if(i*i == N) NumFactors++;
return NumFactors
}
for anyone who hasn't tried the challenge if you run solution(24) it should return 8 as number of factors which are (1, 2, 3, 4, 6, 8,12, 24)
Since the person who wrote the code didn't leave any explanation, can someone who get what's happening kindly explain to me the i*i and the reason of incrementing NumFactors by 2.
The i*i is for checking until squareRoot(N). Because if you have a divisor for a number N then you actually have two divisor. Because the division result is another divisor. For example, in case of 24,
If you take divisor 2, you will find another divisor which is 12. Because 2 X 12 = 24. If you loop through N i.e. 1 to 24 you will get the divisors like this,
2 X 12 = 24
3 X 8 = 24
4 X 6 = 24
6 X 4 = 24
8 X 3 = 24
12 X 2 = 24
24 X 1 = 24
You see we have got redundant values after squareRoot(N). That is why for optimization we are going from 1 to squareRoot(N).
Now about increase factors by 2 is already described above. For the special case when N is a perfect square number like 36 or 49 you will face a case where 6 X 6 = 36 and 7 X 7 = 49 that is why in that case we are increasing the factor by one. Because there is actually on divisor namely 6 and 7 in our case.

Problem on finding number with more than 500 factors

well this is problem number 12 on projecteuler website:
The sequence of triangle numbers is generated by adding the natural numbers. So the 7th triangle number would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. The first ten terms would be:
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
Let us list the factors of the first seven triangle numbers:
1: 1
3: 1,3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28
We can see that 28 is the first triangle number to have over five divisors.
What is the value of the first triangle number to have over five hundred divisors?
and here's my code (I'm new to Javascript)
let num = 1;
let add= 1;
let divisors = [];
while (divisors.length < 500){
divisors = []
for(let i = 1; i <= num; i++){
if(num % i == 0){
divisors.push(i);
}
}
add ++;
num += add;
}
console.log(num - add)
this code run fine when I change the while loop condition to 300 or less.
and this code running on Intel i7 Q740 1.75GHz.
when I try it nothing shows up on console and my question is that's because of my CPU and lack of power or my code has issue? I wait about 20 mins and still nothing as result.
This code is not very efficient as #Vasil Dininski pointed out but you won't reach the max Integer you just have to wait a while for your program to calculate.
I would recommend to optimize your code e.g. by writing a simple function which returns your number of divisors for your current number.
This could look similar to this:
function numberOfDivisors(num) {
var numOfDivisors = 0;
var sqrtOfNum = Math.sqrt(num);
for(var i = 1; i <= sqrtOfNum; i++) {
if(num % i == 0) {
numOfDivisors += 2;
}
}
// if your number is a perfect square you have to reduce it by one
if(sqrtOfNum * sqrtOfNum == num) {
numOfDivisors--;
}
return numOfDivisors;
}
Then you could use this method in your while loop like this:
var maxNumOfDivisors = 500;
var num = 0;
var i = 1;
while(numberOfDivisors(num) < maxNumOfDivisors) {
num += i;
i++;
}
which would return you the correct triangular number.
Please also note that triangular numbers start at 0 which is why my num is 0.
As you might have noticed, this algorithm might be a bit brute-force. A better one would be combine a few things. Let's assume the number we're looking for is "n":
Find all prime numbers in the range [1, square root of n]. You will
be iterating over n, so the sieve of
eratosthenes
will help in terms of efficiency (you can memoize primes you've already found)
Given that any number can be expressed as a prime number to some power, multiplied by a prime number to some power, etc. you can find all the combinations of those primes to a power, which are divisors of n.
This would be a more efficient, albeit a more complicated way to find them. You can take a look at this quora answer for more details: https://www.quora.com/What-is-an-efficient-algorithm-to-find-divisors-of-any-number
If my calculation is not wrong, you add one more to each next divisor from previous divisor and you get final result.
let prev = 0;
for(let i=0; i < 500; i++) {
prev = prev + i;
}
console.log("AA ", prev);

Decompose a number in prime numbers

How can I find a number within the interval (from 1 to given number) which is when decomposed into prime numbers has the maximum amount of them.
Example:
Input: 9
Output: 8
Explanation:
8 = 2 * 2 * 2 (3 primes)
7 = 7 * 1 (1 prime)
6 = 3 * 2 ( 2 primes)
And so on... At the end, we'll see that 8 has the greatest amount of primes in decomposition.
Specification:
If there're several numbers having the same amount of primes in decomposition, return the greatest of them.
Okay, I think I understood your requirement.
Here's a simple script to do what you have asked.
//source of this function: https://jsfiddle.net/JamesOR/RC7SY/
function getAllFactorsFor(remainder) {
var factors = [], i;
for (i = 2; i <= remainder; i++) {
while ((remainder % i) === 0) {
factors.push(i);
remainder /= i;
}
}
return factors;
}
function calculate(x) {
lastFactorCount = 0;
highestNumber = 0;
while (x) {
currentCount = getAllFactorsFor(x).length;
if (currentCount > lastFactorCount) {
lastFactorCount = currentCount;
highestNumber = x;
}
x--;
}
return highestNumber;
}
console.log(calculate(7)); //output: 6
console.log(calculate(11)) //output: 8
This pass the two test cases you have given. I borrowed the getAllFactorsFor() function from a jsfiddle I found since we don't need to reinvent anything ;)
calculate() function takes in an input number, then it loops through every number from x to 0, counting how many factors it has, and it keeps track of the last factor count while decrementing x in each iteration.
Finally it outputs the number with highest factor count. Simple.
Hope it helps!!
Notice that after 2 and 3, the next prime is 5, which is bigger than 2*2 (obviously). Therefore, using 2*2 will ALWAYS be better for amount of prime factors, than any higher prime. The number with the highest amount of 2 as prime factors which is still lower or equal is 2 ** Math.floor(Math.log2(num)). The only thing we need to check is whether replacing the last prime factor 2 with a 3 will still be below the number, as that may happen, and would yield a bigger number. Note again, using more than one 3 would be 3*3 = 9 > 8 = 2*2*2, which cannot be a solution again. All of that together yields that the solution should simply be
const f = num => {
let twoEnd = 2 ** Math.floor(Math.log2(num));
let threeEnd = twoEnd / 2 * 3;
return threeEnd <= num ? threeEnd : twoEnd;
}
Some handling for numbers smaller than 2 may be necessary, depending on the circumstances.

Sorting out numbers in for loops

So I am determining which is a prime number and which isn't, but I am just not understanding how it ends up with the correct output.
So the first starts at 2 and loops by 1 to 100. Easy.
But the second starts at 0, and loops by y + itself, this would make sense, but in determining the primes, it should mess up, atleast I thought
it's like: 1+3 = 4 or 2 + 4 = 6 or 3 + 5 = 8
and that works, but what happens to let's say the 15? that isn't a prime number.
How is numbers like that sorted in the loop?
var prim = [];
var notprim = [];
for(var x = 2; x <= 100; x++){
if(!notprim[x]){
prim.push(x);
for(var y = 0; y <= 100; y = y+x){
notprim[y] = true;
document.write(y);
}
}
}
You have an Array notprim that you can imagine as [undefined × 100], and !!undefined === false, i.e. undefined is falsy
If for some number n you have notprim[n] falsy, you assume it means n must be a prime number and add it to another Array, prim
Then you set all multiples of n to be truthy in notprim, i.e. if n is 3, you set notprim[n * x] = true;, i.e. 0, 3, 6, 9, 12, 15, etc
You then look for the next falsy index in notprim to start again
The reason the first loop starts at 2 is because 2 is the first prime number, starting from 1 or 0 would cause the assumption that "notprim[n] falsy means n is a prime number" to fail
Great, but what about the other loop? Well, one way of going through n * x is to add n to itself x times. When you're thinking of it this way, you can then limit how high you go without knowing a maximum multiplier in advance by looking at the running total, for example in a for loop
for (t = 0; t <= 100; t = t + n)
// t ∈ nℤ, 0 <= t <= 100
but what happens to lets say the 15?
When you've found the prime number 3, you then flag all multiples of 3 to be excluded from your search for primes. 15 is a multiple of 3 so gets flagged as not a prime. Hence your if (!notprim[x]) does not pass
You can reduce the number of iterations this code needs by excluding 0 and x from the second for loop; i.e. begin from the index y = 2 * x

calculate sum of multiples without merging common values

The following code results by combing common values into one:
//3,6,9,12,15------
//5,10,15----------
//result: sum of (3,5,6,9,10,12,15) = 60
int = 0;
for(var i=1;i<16;i++){
if(i%3==0 || i%5==0){
int +=i;
}
}
alert(int);//60
But I wanted to get the output without combining:
//3,6,9,12,15------|should ressult:
//5,10,15----------|75
//result without combining: sum of (3,6,9,12,15,5,10,15) == 75
If you say I should do && instead of || then it will just result common sum i.e. 15 here in example.
So, how can I do?
This will do the trick:
int = 0;
for(var i=1;i<16;i++){
if(i%3==0){
int +=i;
}
if(i%5==0){
int +=i;
}
}
alert(int);//75
Or if you prefer a more compact solution:
int = 0;
for(var i=1;i<16;i++){
int += (i % 3 ? 0 : i) + (i % 5 ? 0 : i);
}
alert(int);//75
Basically, for values that are multiples of 15, you count them twice.
Hints regarding a solution without using a loop: We can break the problem down to just list summing all the multiples of n between a and b-1. This can be computed directly without going through each number by taking a look at the sequence it produces. For n=3, a=1, b=28, this is:
3, 6, 9, 12, 15, 18, 21, 24, 27
Notice now that 27+3=30, 24+6=30, 21+9=30, 18+12=30, and there's only one outlier in the middle, 15. So really all you need to know in order to solve this is the minimum element in the sequence, the maximum element, the number of elements, and the middle element if the the number of elements is odd. (In fact you don't even really need to know the middle number once you realize that it's precisely half of the sum the min and the max).
To help you out a bit more:
var max = Math.floor((b - 1) / n) * n;
var min = a + n - (a % n);
var count = (max - min) / n + 1;

Categories

Resources