Reducing a number on each iteration until it reaches exactly 0 - javascript

I want to reduce n to 0 on the last iteration but my calculations are wrong. Im overlooking something. Right now im doing Math.round(n / loops). I need to find a way to disperse the substraction in such a way so that in the last iteration n becomes 0 while the range between each n´s is constant.
function check(a, b) {
let loops = a / b;
let n = 200;
for (let i = 0; i <= loops; i++) {
console.log(n);
n -= Math.round(200 / loops);
}
}
check(60, 10)
Edit: Im sorry but these downvotes are ridiculous.

The main problem with your code is that the expression n / loop is different in each iteration. You might have intended that this expression was constant, in which case the logic would have been more reasonable.
Use a separate variable that starts with the value of n and then is the subject of the subtractions, but without changing the original value of n that is used in the expression n / loop:
function check(a, b) {
let loops = a / b;
let n = 200; // don't change n after this.
let n2 = n; // use a separate variable for that.
for (let i = 0; i <= loops; i++) {
console.log(Math.round(n2)); // only round in output
n2 -= n / loops; // use n, but only change n2
}
}
check(60,10);

Related

What is the simplest code with a for loop that you would use to represent a Log(n) BigO notation? [duplicate]

Like the Big O notation "O(1)" can describe following code:
O(1):
for (int i = 0; i < 10; i++) {
// do stuff
a[i] = INT;
}
O(n):
for (int i = 0; i < n; i++) {
// do stuff
a[i] = INT;
}
O(n^2):
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
// do stuff
a[i][j] = INT;
}
}
What code can O(log(n)) describe?
Another question:
What solutions are there for "Big O problems" (what to do, when getting a lot of data as an input)?
Classic example:
while (x > 0) {
x /= 2;
}
This will be:
Iteration | x
----------+-------
0 | x
1 | x/2
2 | x/4
... | ...
... | ...
k | x/2^k
2k = x → Applying log to both sides → k = log(x)
Simplest code with a for loop that you would use to represent:
O(1):
function O_1(i) {
// console.log(i);
return 1
}
O(n):
function O_N(n) {
count = 0;
for (i = 0; i < n; i++) {
// console.log(i);
count++;
}
return count
}
O(n²):
function O_N2(n) {
count = 0;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
// console.log(i, j);
count++;
}
}
return count
}
O(Log2(n)):
function O_LOG_2(n) {
count = 0;
for (var i = 1; i < n; i = i * 2) {
count++;
}
return count
}
O(Sqrt(n)):
function O_SQRT(n) {
count = 0;
for (var i = 1; i * i < n; i++) {
// console.log(i);
count++;
}
return count
}
From definition, log(n) (I mean here log with base 2, but the base really doesn't matter), is the number of times, that you have to multiply 2 by itself to get n. So, O(log(n)) code example is:
i = 1
while(i < n)
i = i * 2
// maybe doing addition O(1) code
In real code examples, you can meet O(log(n)) in binary search, balanced binary search trees, many resursive algoritmhs, priority queues.
For O(logn), please have a look at any code that involves divide and conquer strategy
Example: Merge sort & quick sort(expected running time is O(nlogn) in these cases)
Binary Search is an example O(log(n)). http://en.wikipedia.org/wiki/Binary_search_algorithm.
It might be worth emphasizing that the lower complexity algorithms you described are subsets of the the higher complexity ones. In other words,
for (int i = 0; i < 10; i++) {
// do stuff
a[i] = INT;
}
is in O(1), but also in O(n), O(n²), and, if you wanted to be clever, O(log(n)).Why? Because all constant time algorithms are bounded by some linear, quadratic, etc. functions.
What solutions are there for "Big O problems" (what to do, when getting a lot of data as an input)?
This question doesn't make a lot of sense to me. "A lot of data" is a quite arbitrary. Still, keep in mind that Big O isn't the only measure of time complexity; apart from measuring worst case time complexity, we can also examine best-case and average case, though these can be a bit trickier to calculate.
In the case of binary search, you are trying to find the maximum number of iterations, and therefore the maximum number of times the search space can be split in half. This is accomplished by dividing the size of the search space, n, by 2 repeatedly until you get to 1.
Let's give the number of times you need to divide n by 2 the label x. Since dividing by 2, x times is equivalent to dividing by 2^x, you end up having to solve for this equation:
n/2^x = 1, which becomes n = 2^x,
So using logarithm, x = log(n), so BIG - O of binary search is O(log(n))
To reiterate: x is the number of times you can split a space of size n in half before it is narrowed down to size 1.
http://www.quora.com/How-would-you-explain-O-log-n-in-algorithms-to-1st-year-undergrad-student

Trying to optimize my code to either remove nested loop or make it more efficient

A friend of mine takes a sequence of numbers from 1 to n (where n > 0)
Within that sequence, he chooses two numbers, a and b
He says that the product of a and b should be equal to the sum of all numbers in the sequence, excluding a and b
Given a number n, could you tell me the numbers he excluded from the sequence?
Have found the solution to this Kata from Code Wars but it times out (After 12 seconds) in the editor when I run it; any ideas as too how I should further optimize the nested for loop and or remove it?
function removeNb(n) {
var nArray = [];
var sum = 0;
var answersArray = [];
for (let i = 1; i <= n; i++) {
nArray.push(n - (n - i));
sum += i;
}
var length = nArray.length;
for (let i = Math.round(n / 2); i < length; i++) {
for (let y = Math.round(n / 2); y < length; y++) {
if (i != y) {
if (i * y === sum - i - y) {
answersArray.push([i, y]);
break;
}
}
}
}
return answersArray;
}
console.log(removeNb(102));
.as-console-wrapper { max-height: 100% !important; top: 0; }
I think there is no reason for calculating the sum after you fill the array, you can do that while filling it.
function removeNb(n) {
let nArray = [];
let sum = 0;
for(let i = 1; i <= n; i++) {
nArray.push(i);
sum += i;
}
}
And since there could be only two numbers a and b as the inputs for the formula a * b = sum - a - b, there could be only one possible value for each of them. So, there's no need to continue the loop when you find them.
if(i*y === sum - i - y) {
answersArray.push([i,y]);
break;
}
I recommend looking at the problem in another way.
You are trying to find two numbers a and b using this formula a * b = sum - a - b.
Why not reduce the formula like this:
a * b + a = sum - b
a ( b + 1 ) = sum - b
a = (sum - b) / ( b + 1 )
Then you only need one for loop that produces the value of b, check if (sum - b) is divisible by ( b + 1 ) and if the division produces a number that is less than n.
for(let i = 1; i <= n; i++) {
let eq1 = sum - i;
let eq2 = i + 1;
if (eq1 % eq2 === 0) {
let a = eq1 / eq2;
if (a < n && a != i) {
return [[a, b], [b, a]];
}
}
}
You can solve this in linear time with two pointers method (page 77 in the book).
In order to gain intuition towards a solution, let's start thinking about this part of your code:
for(let i = Math.round(n/2); i < length; i++) {
for(let y = Math.round(n/2); y < length; y++) {
...
You already figured out this is the part of your code that is slow. You are trying every combination of i and y, but what if you didn't have to try every single combination?
Let's take a small example to illustrate why you don't have to try every combination.
Suppose n == 10 so we have 1 2 3 4 5 6 7 8 9 10 where sum = 55.
Suppose the first combination we tried was 1*10.
Does it make sense to try 1*9 next? Of course not, since we know that 1*10 < 55-10-1 we know we have to increase our product, not decrease it.
So let's try 2*10. Well, 20 < 55-10-2 so we still have to increase.
3*10==30 < 55-3-10==42
4*10==40 < 55-4-10==41
But then 5*10==50 > 55-5-10==40. Now we know we have to decrease our product. We could either decrease 5 or we could decrease 10, but we already know that there is no solution if we decrease 5 (since we tried that in the previous step). So the only choice is to decrease 10.
5*9==45 > 55-5-9==41. Same thing again: we have to decrease 9.
5*8==40 < 55-5-8==42. And now we have to increase again...
You can think about the above example as having 2 pointers which are initialized to the beginning and end of the sequence. At every step we either
move the left pointer towards right
or move the right pointer towards left
In the beginning the difference between pointers is n-1. At every step the difference between pointers decreases by one. We can stop when the pointers cross each other (and say that no solution can be obtained if one was not found so far). So clearly we can not do more than n computations before arriving at a solution. This is what it means to say that the solution is linear with respect to n; no matter how large n grows, we never do more than n computations. Contrast this to your original solution, where we actually end up doing n^2 computations as n grows large.
Hassan is correct, here is a full solution:
function removeNb (n) {
var a = 1;
var d = 1;
// Calculate the sum of the numbers 1-n without anything removed
var S = 0.5 * n * (2*a + (d *(n-1)));
// For each possible value of b, calculate a if it exists.
var results = [];
for (let numB = a; numB <= n; numB++) {
let eq1 = S - numB;
let eq2 = numB + 1;
if (eq1 % eq2 === 0) {
let numA = eq1 / eq2;
if (numA < n && numA != numB) {
results.push([numA, numB]);
results.push([numB, numA]);
}
}
}
return results;
}
In case it's of interest, CY Aries pointed this out:
ab + a + b = n(n + 1)/2
add 1 to both sides
ab + a + b + 1 = (n^2 + n + 2) / 2
(a + 1)(b + 1) = (n^2 + n + 2) / 2
so we're looking for factors of (n^2 + n + 2) / 2 and have some indication about the least size of the factor. This doesn't necessarily imply a great improvement in complexity for the actual search but still it's kind of cool.
This is part comment, part answer.
In engineering terms, the original function posted is using "brute force" to solve the problem, iterating every (or more than needed) possible combinations. The number of iterations is n is large - if you did all possible it would be
n * (n-1) = bazillio n
Less is More
So lets look at things that can be optimized, first some minor things, I'm a little confused about the first for loop and nArray:
// OP's code
for(let i = 1; i <= n; i++) {
nArray.push(n - (n - i));
sum += i;
}
??? You don't really use nArray for anything? Length is just n .. am I so sleep deprived I'm missing something? And while you can sum a consecutive sequence of integers 1-n by using a for loop, there is a direct and easy way that avoids a loop:
sum = ( n + 1 ) * n * 0.5 ;
THE LOOPS
// OP's loops, not optimized
for(let i = Math.round(n/2); i < length; i++) {
for(let y = Math.round(n/2); y < length; y++) {
if(i != y) {
if(i*y === sum - i - y) {
Optimization Considerations:
I see you're on the right track in a way, cutting the starting i, y values in half since the factors . But you're iterating both of them in the same direction : UP. And also, the lower numbers look like they can go a little below half of n (perhaps not because the sequence start at 1, I haven't confirmed that, but it seems the case).
Plus we want to avoid division every time we start an instantiation of the loop (i.e set the variable once, and also we're going to change it). And finally, with the IF statements, i and y will never be equal to each other the way we're going to create the loops, so that's a conditional that can vanish.
But the more important thing is the direction of transversing the loops. The smaller factor low is probably going to be close to the lowest loop value (about half of n) and the larger factor hi is probably going to be near the value of n. If we has some solid math theory that said something like "hi will never be less than 0.75n" then we could make a couple mods to take advantage of that knowledge.
The way the loops are show below, they break and iterate before the hi and low loops meet.
Moreover, it doesn't matter which loop picks the lower or higher number, so we can use this to shorten the inner loop as number pairs are tested, making the loop smaller each time. We don't want to waste time checking the same pair of numbers more than once! The lower factor's loop will start a little below half of n and go up, and the higher factor's loop will start at n and go down.
// Code Fragment, more optimized:
let nHi = n;
let low = Math.trunc( n * 0.49 );
let sum = ( n + 1 ) * n * 0.5 ;
// While Loop for the outside (incrementing) loop
while( low < nHi ) {
// FOR loop for the inside decrementing loop
for(let hi = nHi; hi > low; hi--) {
// If we're higher than the sum, we exit, decrement.
if( hi * low + hi + low > sum ) {
continue;
}
// If we're equal, then we're DONE and we write to array.
else if( hi * low + hi + low === sum) {
answersArray.push([hi, low]);
low = nHi; // Note this is if we want to end once finding one pair
break; // If you want to find ALL pairs for large numbers then replace these low = nHi; with low++;
}
// And if not, we increment the low counter and restart the hi loop from the top.
else {
low++;
break;
}
} // close for
} // close while
Tutorial:
So we set the few variables. Note that low is set slightly less than half of n, as larger numbers look like they could be a few points less. Also, we don't round, we truncate, which is essentially "always rounding down", and is slightly better for performance, (though it dosenit matter in this instance with just the single assignment).
The while loop starts at the lowest value and increments, potentially all the way up to n-1. The hi FOR loop starts at n (copied to nHi), and then decrements until the factor are found OR it intercepts at low + 1.
The conditionals:
First IF: If we're higher than the sum, we exit, decrement, and continue at a lower value for the hi factor.
ELSE IF: If we are EQUAL, then we're done, and break for lunch. We set low = nHi so that when we break out of the FOR loop, we will also exit the WHILE loop.
ELSE: If we get here it's because we're less than the sum, so we need to increment the while loop and reset the hi FOR loop to start again from n (nHi).

JavaScript - Factorial explanation

I wanted someone to basically help me understand what each line of code is doing and help me comment each line (if applicable) so that it can help explain to another person what it's doing. It'd be awesome if one can just give second eyes and ensure that the code is actually good - I'm trying to get my head around Factorial/Recursion, and did some research and found these solutions for this.
I was given this scenario:
For positive n, factorial is n! = n(n−1)!   (e.g. 5! = 5 * 4
* 3 * 2 * 1)*
Here's what I've found for this scenario:
// Prompt user to enter a number to calculate the factorial
var num = prompt("What number do you want to find the factorial of?");
var factorial = function(n) {
if (n == 0) {
return 1;
} else {
product = 1;
for (i = 1; i < n; i++) {
product *= i;
}
return product;
}
}
console.log(factorial(num));
Recursive
Create a recursive algorithm to calculate the factorial using every second
number as shown in examples below:
5! = 5 * 3 * 1 = 15
6! = 6 * 4 * 2 = 48
As for the cursive part, this is added onto the above code and is written in the following -
//  recursive
var factorial = function(n) {
if (n == 0) {
return 1;
} else {
return n * factorial(n - 1);
}
}
console.log(factorial(num));
Would appreciate your assistance on this - Apologies if this has already been answered, please direct me to another thread if this has been already posted. Thanks!
You don't need recursion for that:
/**
* Calculate factorial, optionally using a difference other than 1 with previous value.
* Example: factorial(6, 2) // 6*4*2 = 48
*/
var factorial = function(n, d) {
if (!d) {d = 1;}
var product = 1;
while (n > 1) {
product *= n;
n -= d;
}
return product;
};
console.log(factorial(6, 2)); // 48
console.log(factorial(6)); // 720
Note: Declare local variables inside the function with keyword 'var'. Otherwise they become globals and the second time you attempt to use a function may produce wrong results.
Usually, writing a function for Factorial is an exercise on writing recursive function. The first example code is not recursive and just an overly complicated way of calculating a factorial by multiplying the numbers iteratively so I'll skip that.
The second code is recursive, and it is following the recursive definition of factorial in your usual mathematics:
f: N => N, f(x) = x! = { x < 1 : 1, else : x (x - 1)! }
Or equivalently in JavaScript:
let fac = n => n < 1 ? 1 : n * fac(n - 1);
An expansion of an example computation would look like:
5!
5(4!)
5(4(3!))
5(4(3(2!)))
5(4(3(2(1))))
5(4(3(2(1(0!)))))
5(4(3(2(1(1)))))
120

Why does my factorial function always return one?

I am trying to write a piece of code to solve a Coderbyte challenge, to calculate a number's factorial. Every time I run it, the factorial generated is one. What am I doing wrong?
var num
var array1 = new Array();
function FirstFactorial(num) {
for (var i = num; i>0; i--){ // 8 , 7, 6 , 5
for (var y = 0; y<num ; y++){ // 0, 1, 2, 3, 4
array1[y]=i; // we have an array that looks like [8,7,6,5,4,3,2,1]
};
};
var sum = 1
for (var x = 0; x<array1.length; x++){ // now I want to run up that array, reading the #s
sum = sum * array1[x];
return sum;
};
return sum
};
A few issues.
1/ This is minor but, when you multiply two numbers, you get a product, not a sum.
2/ You returned the value from within the loop which would mean, even if you fixed the other problems, it would return prematurely without having multiplied all the numbers.
3/ Your nested loop does not fill your array the way you describe, you should check it after population. Think about your loops expressed as pseudo-code:
for i = num downto 1 inclusive:
for y = 0 to num-1 inclusive:
array1[y] = i
You can see that the inner loop is populating the entire array with the value of the current i. So the last iteration of the outer loop, where i is one, sets the entire array to ones.
4/ In any case, you don't need an array to store all the numbers from 1 to n, just use the numbers 1 to n directly. Something like (again, pseudo-code):
def fact(n):
prod = 1
for i = 2 to n inclusive:
prod = prod * i
return prod
This is a much easier way to calculate the factorial of a number.
function factorial(num)
{
if(num === 1)
{
return num;
}
return num * factorial(num - 1);
}
However to fix your code you need to fix the initial loop that loads the numbers into the array. as well as remove the return statement in the bottom loop. Like so.
function FirstFactorial(num) {
for (var i = num; i>0; i--) {
array1[num - i] = i;
};
var sum = 1
for (var x = 0; x < array1.length; x++){ // now I want to run up that array, reading the #s
sum = sum * array1[x];
};
return sum
};

How to convert this Pascal Code to JavaScript?

I am trying to make simple JS code to find out the amount a number from 1 to 9 occurs in a given string. I have this Pascal code that works:
Var n,i:longint;
A:array[0..9] of byte;
Begin
write('Введите число: ');readln(n);
While n>0 do
Begin
A[n mod 10]:=A[n mod 10]+1;
n:=n div 10;
End;
For i:=0 to 9 do
writeln('The number ',i,' occurs ',A[i],' amount of times');
readln;
End.
In JS I ended up with this, but that seems to have a never-ending loop:
function plosh(form) {
var list = new Array(9);
var n = form.a.value;
while (n>0) {
a = n % 10;
list[a] = list[a]+1;
n = n % 10;
}
for (var i=0; i<=9; i++)
{
alert("Цифра"+i+"встречается"+A[i]+"раз");
}
}
Would appreicate any help on where I am going wrong with this. Thanks in advance!
n = n % 10 leaves n unchanged as soon as it's lower than 10, so it will usually never reach 0, hence the endless loop.
The div operator in Pascal makes an integral division.
Change
n = n % 10
to
n = Math.floor( n / 10 );
You also have another problem : you're not properly initializing your array so you're adding 1 to undefined. Fix that like this :
function plosh(form) {
var a,
list = [],
n = form.a.value;
while (n>0) {
a = n % 10;
list[a] = (list[a]||0)+1;
n = Math.floor( n / 10 );
}
for (var i=0; i<=9; i++) {
console.log("Цифра"+i+"встречается"+A[i]+"раз"); // <- less painful than alert
}
}
n:=n div 10;
was translated as:
n = n % 10;
but should be:
n = Math.floor(n / 10);
Edit: Also, you define an array [0..9] in Pascal, which means 10 elements. When you call Array(9) you only create 9 elements.

Categories

Resources