The for loop in this program isn't working as expected - javascript

It is supposed to print prime n numbers. The for loop will run from 2 to x which will iterate each time. if i == x then it means that the number was not divisible and so it should be printed as prime
var n;
var x = 2;
var i;
function prime(n) {
while (n) {
for (i = 2; i < x; i++) {
if (x % i == 0) {
break;
}
if (i == x) {
document.write(i + " ");
n--;
}
x++;
}
}
}
prime(10);

When you try to execute this code, this will never get into the for loop and goes into an infinite while loop. You have got:
i = 2; i < x;
The i will never be less than x. And it doesn't enter the for loop and comes out. And n will always be 10, that goes on into an infinite loop.
You need to use the modulus operator to check if a number is divisible by them.

Maybe change your approach a bit and try to find the first X prime number using just for loops.
var n;
var x = 2;
var i;
function prime(n) {
if (n <= 0) return;
var i, j, p_no = 0, res = [];
for (i = 2; ; i++) {
var ifPrime = true;
for (j = 2; ifPrime && j <= Math.sqrt(i); j++) {
if (i % j === 0) ifPrime = false;
}
if (ifPrime) {
res.push(i);
console.log(i + ' ');
p_no++;
if (p_no === n) return res.toString();
}
}
}
document.getElementById('prime').innerHTML = prime(10);
<p id="prime"></p>

What's happening when the code runs is what Praveen describes. I want to address how you got to your algorithm in the first place.
It looks like you're trying to print all primes less than a specific number n. You've jumbled different aspects of your algorithm together. Specifically, you've combined a loop that exists to find whether a number is prime with a loop over all numbers less than n.
The first thing you can do to help manage this complexity is to use methods. If you had a method isPrime(k) that returns true or false if a given number is prime, then your function's main loop looks much simpler, and separates the two problems from each other:
function prime(n) {
for (var i = n; i > 1; i--) {
if (isPrime(i)) {
document.write(i + " ");
}
}
}
Then you can focus on defining the isPrime method separately, without getting its parts confused with the main loop:
function isPrime(k) {
for (var i = 2; i < k; i++) {
if (k % i == 0) {
return false;
}
}
return true;
}
Methods are a fantastic way of keeping algorithms simpler by isolating their components. They're building blocks one can use to make more complex systems without having to keep track of the whole. It lets you make smaller changes, each encapsulated from other concerns, meaning you have less to keep in your mind while you're making those changes. The less you have to keep in your mind, the easier it is to spot mistakes.

Related

Varying number of related nested for loops

I am attempting to determine all possible sums from rolling n dice, where n is not known at compile time.
For two dice, the solution is straightforward, just iterate through both dice and add each possible side to each other. If passing in 2 6-sided dice, the sorted results would be: [2,3,3,4,4,4,5,5,5,5,6,6,6,6,6,7,7,7,7,7,7,8,8,8,8,8,9,9,9,9,10,10,10,11,11,12]
I tried to expand this solution to any n dice, but I realized that I need n for loops.
for(let i = 0; i < numDice; i++)
{
dice.push(sides);
}
for(let i = 0; i < numSides; i++)
{
for(let j = 1; j < dice.length; j++)
{
for(let k = 0; k < numSides; k++)
{
results.add(dice[0][i] + dice[j][k]);
}
}
}
I also attempted a recursion-based approach as the first question below suggested. I believe it will loop the correct number of times, but I couldn't figure out how to define my summing function without introducing yet more loops.
function doCallMany(numDice, numSides, sumFunc)
{
if(numDice == 0)
{
sumfunc(numDice, numSides) //?
}
else
{
for(let i = 0; i < numSides; i++)
{
doCallMany(numDice--, numSides, sumFunc)
}
}
}
I looked at similar questions here and here but they do not answer my question. The first doesn't because the action I need to perform in the loops is not independent. The second is close, but the answers rely on Python-specific answers.
The comment about the complexity of the solutions is correct. It gets big quickly. Having said that, to address your original question, you can do this with a fairly simple recursive function for small input. Basically you start with an array of dice, pop one off add it to a sum and recurse with that sum and the rest of the array.
For example:
function sums(dice, sum = 0, ans = []) {
if (dice.length === 0) ans.push(sum) // edge case, no more dice
else {
let d = dice[0]
for (let i = 1; i <= d; i++) {
sums(dice.slice(1), sum + i, ans) // recurse with remaining dice
}
return ans
}
}
// two six-sided dice
let ans = sums([6, 6])
console.log(JSON.stringify(ans.sort((a, b) => a - b)))
// three three-sided dice
ans = sums([3, 3, 3])
console.log(JSON.stringify(ans.sort((a, b) => a - b)))
I suggest you use the backtracking method.
It lets you vary the number of loops you want to execute. You can even execute a random number of loops, as the number of loops can be held in a variable.

Finding he largest palindromic number, which is the product of two simple (prime) five-digit numbers. Javascript

I was trying to write a program that returns the largest palindromic number, which is the product of two simple five-digit numbers, and returns the factors themselves.
A prime number is a natural number that is divided only by 1 and itself (2, 3, 5, 7, 11, ...)
A palindromic number reads the same both ways (for example, ABBA).
if(isPalin(mul) && isPrime(i) && isPrime(j))
function isPrime(i){
for (var k = 2; k <= i; k++) {
if (i%k===0 && i!==k) {
return false;
}
}
return true;
}
<!--code-->
<script>
function largestPalindrome(){
for(var i = 99999; i>10000; i--){
for(var j = 99999; j>10000; j--){
var mul = j*i;
if(isPalin(mul) && isPrime(i) && isPrime(j)){
return i * j;
}
}
}
}
function isPalin(i){
return i.toString() == i.toString().split("").reverse().join("");
}
function isPrime(i){
for (var k = 2; k <= i; k++) {
if (i%k===0 && i!==k) {
return false;
}
}
return true;
}
console.log(largestPalindrome());
</script>
When I run this program it does not display anything in the console and I am not sure why.
Look this link for time-complexity of algorithms. Also this to see how time-complexity can influence to your program efficiency.
This part is not very precise but it can help. Your first loop runs 99999-10000 time. Also this holds for second loop. The isPrime in the worst case runs (99999). So if (i%k===0 && i!==k) return false; runs total_ops = (99999-10000)^2*(99999) times(we skip other part of your code). If your program written in c++ which is more faster than java-script it can run about 2*(10^8) simple operation per second. Your program run time is about(obviously more than) total_ops/(2*10^8) (I suggest calculate it to have an estimation...).
PS: You can put print to your functions to ensure about their progress...
Problem:: Time Complexity
improvements
isPrime()
function isPrime(n)
{
// Corner cases
if (n <= 1) return false;
if (n <= 3) return true;
// This is checked so that we can skip
// middle five numbers in below loop
if (n%2 == 0 || n%3 == 0) return false;
for (var i=5; i*i<=n; i=i+6)
if (n%i == 0 || n%(i+2) == 0)
return false;
return true;
}
you isprime function is not optimized one. You should use this.
Don't find every prime number 2 times.! Just find all prime numbers once, store them into a list, and then pick every number from prime list and check if it is palindrome.
var primelist = [];
for(var i = 99999; i > 10000; i++)
{
if(isprime(i))
{
primelist.push(i);
}
}
for (var i = 0; i < primelist.length; i++) {
for (var j = 0; j < primelist.length; j++)
{
if(isPalindrome(i*j))
{
// Number you want.
return (i*j);
}
}
}
to check , start from the largest prime numbers.
a 5 digit number starts from 10000 to 99999 instead of 11111 to 99999. Although, It does not change the output of the function.

Finding Least Common Multiple using Table Method

Find the least common multiple of the provided parameters using Table Method that can be evenly divided by both, as well as by all sequential numbers in the range between these parameters. There will only be two parameters. For ex [1,3], find the lcm of 1,2,3.
Note - It might create an infinite loop
function smallestCommons(arr) {
var nums = [];
var multiples = [];
if(arr[0]>arr[1]) {
var bigger = arr[0];
} else {
var bigger = arr[1];
}
for(var i=bigger;i>0;i--) {
nums.push(i);
console.log(i);
}console.log(nums + " nums");
var sums = 0;
while(sums != nums.length) {
for(var k=0;k<nums.length;k++) {
if(nums[k] % 2 === 0) {
nums[k] = nums[k]/2;
multiples.push(2);
} else if(nums[k] % 3 === 0) {
nums[k] = nums[k]/3;
multiples.push(3);
}else if(nums[k] % 5 === 0) {
nums[k] = nums[k]/5;
multiples.push(5);
}else if(nums[k] % 7 === 0) {
nums[k] = nums[k]/7;
multiples.push(7);
}else if(nums[k] === 1) {
break;
}else {
nums[k] = nums[k]/nums[k];
multiples.push(nums[k]);
}
}
for(var j = bigger; j>0;j--) {
sums = sums + nums[j];
}
}
var scm = [multiples].reduce(function(a,b){console.log(a*b)}); return scm
}
smallestCommons([1,5]);
I found this to be a simple solution, It works wonders;
Loop through all possible numbers, beginning with lower bound input (var i)
for every number, test divisibility by each number between and including input bounds (var j)
if i meets all criteria return it as answer, otherwise increment i by 1 and try again
click here for explanation of ? operator in variable initialization
function smallestCommons(arr) {
//set variables for upper and lower bounds
//incase they aren't entered in ascending order
var big = arr[0] < arr[1] ? arr[1]:arr[0],
small = arr[0] < arr[1] ? arr[0]:arr[1],
i = small;
//loop through all numbers, note the possibility of an infinite loop
while(true){
//test each number for divisibility by by both upper and lower
//bounds, as well as by all sequential numbers inbetween
for(var j = small; j <= big; j++){
if(i % j === 0){
if(j===big){
return i;
}
}else {
break;
}
}
i++;
}
}
smallestCommons([1,5]); //60
What you need is find the LCM in range (n, m) ?
Finding least common multiples by prime factorization seems better.
You can use Legendre's formula to find all prime factors of n! and m! , then just do a simple subtraction.

Prime Factor Calculator JS - Can't find infinite loop

So I was trying to go back over my problem solving abilities and wanted to redo my prime factor calculator. Code refactoring, more efficient, etc as I was a beginner at JS when I made it.
In recreating it I have come across a rather large issue - an infinite loop. Now, I've broken down my function into different parts and called them separately - they work fine. The main function itself even works fine, so long as the number is 10 or less. But for some reason whenever I call the function with a parameter greater than 10 there is an infinite loop.
I'm sorry if the answer is glaringly obvious, it's quite late at night. I just can't seem to spot it.
The plain code is here:
var findPrimeFactors = function (number) {
var isPrime = function (number) {
var primes = [];
for (i = 2; i < number; i++) {
if (number % i === 0) {
return false;
}
}
primes.push(number);
return primes;
};
var findFactors = function (number) {
var factors = [];
for (i = 2; i < number; i++) {
if (number % i === 0) {
factors.push(i);
}
}
return factors;
};
var factors = findFactors(number);
var primes = [];
for (i = 0; i < factors.length; i++) {
primes += isPrime(factors[i]);
}
return primes;
};
console.log(findPrimeFactors(10));
The fiddle for the code is here: https://jsfiddle.net/uk26q4ff/
Thanks everyone!
Likely you are hitting this because in each function you aren't declaring i so it is using it from the global scope.
I found a couple of bugs.
Your isPrime function should return either true or false, not an array
the loop in findFactors should include the 'number' value (changed < to <=)
The infinite loops was cause by using the same variable i in every
loop.
Finally I changed the following I changed the following line
at the end: if (isPrime(factors[k])) primes.push(factors[k]);
Here is how I would do it:
var findPrimeFactors = function (number) {
var isPrime = function (number) {
var primes = [];
for (i = 2; i < number; i++) {
if (number % i === 0) {
return false;
}
}
//primes.push(number);
//return primes;
return true;
};
var findFactors = function (number) {
var factors = [];
for (j = 2; j <= number; j++) {
if (number % j === 0) {
factors.push(j);
}
}
return factors;
};
var factors = findFactors(number);
var primes = [];
for (k = 0; k < factors.length; k++) {
//primes += isPrime(factors[k]);
if (isPrime(factors[k])) primes.push(factors[k]);
}
return primes;
};
console.log(findPrimeFactors(37));

string addition I coderbyte completely stumped

Can anyone explain the solution to me like a 6 year old? I haven't been able to make sense of the solutions. Maybe some code comments?
Thank you.
I've spent the last 2 hours on coderbyte trying to solve this one. Here's the question:
Have the function ArrayAdditionI(arr) take the array of numbers stored
in arr and return the string true if any combination of numbers in the
array can be added up to equal the largest number in the array,
otherwise return the string false. For example: if arr contains [4, 6,
23, 10, 1, 3] the output should return true because 4 + 6 + 10 + 3 =
23. The array will not be empty, will not contain all the same elements, and may contain negative numbers.
I've scoured the internet, read through a bunch of people's solutions from the people's answers on coderbyte itself, but without any comments I'm really struggling to figure out how this is done. I've started over countless times, so I'm not even sure if this last attempt is any better or not.
I understand that I'll need to loop through somehow and test every combination index 5, index 4, index 3, index 2, index 1, AND every combination of less than all of those (ie just index 5 and index 3). I just can't figure out how to do that. If I knew the list would always be an array of 5 numbers, and it required all 5, I would write 5 loops all equally nested inside of one big one, right? However, with the added complexity of not requiring all numbers and not knowing the length of the array for all cases, I am completely stumped. I tried using Math.floor(Math.random() * array.length); to generate a list of numbers... but that didnt work either.
function ArrayAdditionI(arr) {
var longest = arr.sort( function(a,b) { return a-b });
var longest = longest[longest.length - 1];
var sumArr = function (arrb) {
var sum = 0;
for (var z = 0; z < arrb.length; z++){
sum += arrb[z];
}
return sum;
};
for (var i = 0; i > arr.length; i++) {
for (var y = 0; y > arr.length; i++) {
testArr.push(arr[i]);
if (sumArr(testArr) === longest) {
return true;
}
testArr.push(... its 4am and I'm stumped!...)
}}
// code goes here
return false;
}
// keep this function call here
// to see how to enter arguments in JavaScript scroll down
ArrayAdditionI(readline());
A fairly simple to understand and common solution to the problem is as follows. It basically starts by looping forward through the array (loop i) by adding each subsequent number (loop j). If loop j finishes without a solution, loop k begins and removes each subsequent number. Then i increments and the loops start over.
function ArrayAdditionI(arr) {
arr.sort(function(a,b){return a - b})
var largest = arr.pop(); // Set largest to last (largest) array value
var sum = 0;
for (var i = 0; i < arr.length; i++){ // Start outer loop
sum += arr[i];
for (var j = 0; j < arr.length; j++){ // Start inner to begin sum
if (i != j) { // Ensure we don't add the same array index to itself
sum += arr[j];
console.log(sum);
if (sum == largest) {
return true;
}
}
}
for (var k = 0; k < arr.length; k++) { // If no match, start 2nd loop to re-iterate removing index values
if (i != k) {
sum -= arr[k];
console.log(sum);
if (sum == largest) {
return true;
}
}
}
sum = 0; // Reset sum for outer loop
}
return false;
}
The comment by thefourtheye basically told you the name of the problem and what to search for on google.
Solutions in java code would be the following...
1) find all subsets that sum to a particular value
This is the theory and pseudocode.
2) How to implement the Sum of Subsets problem in Java
Change the code to return what you wish if number of sets > 0 .
3) Modify GetAllSubsetByStack in below code to stop when a set is found:
https://codereview.stackexchange.com/questions/36214/find-all-subsets-of-an-int-array-whose-sums-equal-a-given-target
We did a similar recursion for a "MakeChange" algorithm at a meetup I went to last night. This morning I took a look at this problem with fresh eyes after not looking at it for a few weeks. Here's what I came up with.
Essentially: sort the array to biggest to smallest, shift that one off and declare it "goal", then recursively reduce an array by slicing it smaller and smaller each recurse, when the array reaches 0 length, randomize the original array and begin reducing again.
return true if goal = total (ie the reduce)
return false if ive randomized the array more than 1000 times.
function ArrayAdditionI(arr) {
var originalArr = arr.sort(function(a,b) {return b-a});
var goal = arr.shift();
var counter = 0;
function randomArray(array) {
for (var i = array.length - 1; i > 0; i -= 1){
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
function recurse(arr) {
if (arr.length == 0){
counter++
var newArr = randomArray(originalArr);
return recurse(newArr);
} else {
var total = arr.reduce(function(a,b) {return a+b});
if (goal == total){
return true
} else if (counter == 1000) {
return false
} else {
newArr = arr.slice(1);
return recurse(newArr);
}
}
}
// code goes here
return recurse(originalArr);
}

Categories