Project Euler #2, Fibonacci, javascript attemp - javascript

I was attempting to do some problems on project euler. For the second one I did get the correct answer but I cheated a bit.
Heres the problem:
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
Heres my code:
var fib = [1,2];
var i = 0;
var sum = 0;
while (fib[0] + fib[1] < 4000000){
i = fib[0] + fib[1];
console.log(i); //just to show myself the number came out correctly.
fib[0] = fib[1];
fib[1] = i;
if (i % 2 === 0){
sum += i;
}
}
console.log(sum + 2);
I added sum by 2 because I can't figure a way for the code to add the initial fib[1], which is a even number itself. Thanks.

Simple solution
var sum = 0;
var term1 = 1;
var term2 = 1;
while (term2 < 4000000) {
term2 = term1 + term2;
term1 = term2 - term1;
sum += term2 % 2 === 0 ? term2 : 0;
}
console.log(sum);

If you start with [1, 2], the first fibonacci number that you get is 3.
In your loop you have:
i = 1+2 = 3
i = 2+3 = 5
So simply start with [0, 1]:
i = 0+1 = 1
i = 1+1 = 2
i = 1+2 = 3
Fixed code:
var fib = [0,1];
var i = 0;
var sum = 0;
while (fib[0]+fib[1] < 4000000){
i= fib[0]+fib[1];
fib[0]=fib[1];
fib[1]=i;
if(i%2 === 0){
sum += i;
}
}
console.log(sum);

for (var sum = 0, i = 0, j = 0, k = 1; 4e6 > j + k; i++) i = j + k, j = k, k = i, sum += 0 == i % 2 ? i : 0;
It could help you.

let num1 = 0;
let num2 = 1;
let total = 0;
let num3 = 0;
let i = 0;
while(num1 + num2 < 4000000){
num3 = num1 + num2;
num1 = num2; //as loop keep going is changes the position of number
num2 = num3; //as loop keep going is changes the position of number
if(num3 % 2 === 0 ){ // check weather number is even or not
total += num3; //every even number gets added
}
i++
}
console.log(total);

function firstNofFibonacci(n)
{
let fibArr = [];
for (let i = 0; i < n; i++) {
if (fibArr.length > 1) {
fibArr.push(fibArr[fibArr.length - 1] +
fibArr[fibArr.length - 2]);
} else {
fibArr.push(i);
};
};
return fibArr;
}

This is my code for the same problem. It is not perfect but I hope this will help someone who reads this.
function fibonacci(stop) {
var a = 1, b = 0, c, storage = []
for (var i = 0; a < stop; i++) {
c = a
a = a + b
b = c
if (b%2 == 0) {
let even = b
storage.unshift(even)
}
}
var all = storage.reduce((x, y) => {return x + y}, 0)
console.log(all)
}
fibonacci(4000000); // 4613732
well, what I did here is that I create a function with the stop parameter (where you tell the function to stop) and then I create variables to make the Fibonacci sequence and create a variable where I can store the even values. Then push all the even values in the array, at the end of the function I add all the values in a variable and console.log() the value
If you have suggestions or comments all ears :)

Related

Not able to get value after Do...While loop

Question: Create a function that takes a positive integer and returns the next bigger number that can be formed by rearranging its digits. For example:
12 ==> 21
513 ==> 531
2017 ==> 2071
//nextBigger(num: 12) // returns 21
//nextBigger(num: 513) // returns 531
//nextBigger(num: 2017) // returns 2071
I am trying to compare two Array and get correct array as answer. In do...while loop I am comparing the two array by increment second array by one.
function nextBigger(n){
let nStrg = n.toString();
let nArr = nStrg.split('');
function compareArr(Ar1,Ar2){
if(Ar2.length>Ar1.length){
return false;
}
for(let i=0; i<Ar1.length; i++){
let num = Ar1[i];
for(let j=0; j<Ar2.length; j++){
if(Ar2.lastIndexOf(num) !== -1){
Ar2.splice(Ar2.lastIndexOf(num), 1);
break;
}
else{
return false;
break;
}
}
}
return true;
}
let nextNumArr;
let m = n;
do{
let nextNum = m+1
m=nextNum
let nextNumStrg = nextNum.toString();
nextNumArr = nextNumStrg.split('')
console.log(compareArr(nArr, nextNumArr))
}
while(compareArr(nArr, nextNumArr) == false)
console.log(nextNumArr)
return parseInt(nextNumArr.join())
}
nextBigger(12);
This gives me empty array at the end;
[2,0,1,7].join() will give you '2,0,1,7', can use [2,0,1,7].join('') and get '2017'
All looks a bit complicated. How about:
const nextLarger = num => {
const numX = `${num}`.split(``).map(Number).reverse();
for (let i = 0; i < numX.length; i += 1) {
if ( numX[i] > numX[i + 1] ) {
numX.splice(i, 2, ...[numX[i+1], numX[i]]);
return +(numX.reverse().join(``));
}
}
return num;
};
const test = [...Array(100)].map(v => {
const someNr = Math.floor(10 + Math.random() * 100000);
const next = nextLarger(someNr);
return `${someNr} => ${
next === someNr ? `not possible` : next}`;
}).join('\n');
document.querySelector(`pre`).textContent = test;
<pre></pre>
See also
function nextbig(number) {
let nums = []
number.toString().split('').forEach((num) => {
nums.push(parseInt(num))
})
number = nums
n = number.length
for (var i = n - 1; i >= 0; i--) {
if (number[i] > number[i - 1])
break;
}
if (i == 1 && number[i] <= number[i - 1]) {
return 'No greater possible'
}
let x = number[i - 1];
let smallest = i;
for (let j = i + 1; j < n; j++) {
if (number[j] > x &&
number[j] < number[smallest])
smallest = j;
}
let temp = number[smallest];
number[smallest] = number[i - 1];
number[i - 1] = temp;
x = 0
for (let j = 0; j < i; j++)
x = x * 10 + number[j];
number = number.slice(i, number.length + 1);
number.sort()
for (let j = 0; j < n - i; j++)
x = x * 10 + number[j];
return x
}
console.log(nextbig(12))
console.log(nextbig(513))
console.log(nextbig(2017))
In compareArr you are deleting elements as you find them, which is correct to do, to make sure duplicates actually occur twice etc. However, that also deletes the elements from nextNumArr in the calling context, because the array is passed by reference and not by value. You need to do a manual copy of it, for example like this: compareArr(nArr, [...nextNumArr]).
I have used a different approach, first I search for all possible combinations of the given numbers with the permutator function. This function returns an array of possible numbers.
Then I sort this array of combinations and look for the index of the given number in the main function.
Once I have this index I return the position before the given number.
function nextbig(num){
function permutator(inputArr){
let result = [];
const permute = (arr, m = []) => {
if (arr.length === 0) {
result.push(m)
} else {
for (let i = 0; i < arr.length; i++) {
let curr = arr.slice();
let next = curr.splice(i, 1);
permute(curr.slice(), m.concat(next))
}
}
}
permute(inputArr)
return result;
}
let arrNums = num.toString().split('')
let combinations = permutator(arrNums).map(elem => parseInt(elem.join("")))
combinations.sort((a, b) => {
return b - a
})
let indexOfNum = combinations.findIndex(elem => elem === num)
let nextBigIndex = indexOfNum <= 0 ? 0 : indexOfNum - 1
return (combinations[nextBigIndex])
}
console.log(nextbig(12))
console.log(nextbig(517))
console.log(nextbig(2017))

JavaScript: Shuffling a deck, but it does NOT create a new shuffled deck each time using the original list

I am trying to shuffle a deck. I take a number of cards as input. For example, numCards = 5, so the deck (list) becomes [0,1,2,3,4]. The problem is that the while loop in the test_order(i,j,l) function is not shuffling properly. Function console.log(m) should print a new shuffled deck/list using the original list (l) but it keeps printing [0,1,2,3,4] after the first correct shuffle. It should create a newly shuffled deck each time using the original list, instead, it keeps repeating the original list or 1st shuffled list.
The purpose of the program is to find the probability of the number of times a card labeled i is above card labeled j after shuffles.
function list(numCards){
var newList = []
var i = 0;
while (i < numCards){
newList.push(i);
i++;
}
return newList
}
function top_to_random(l){
while(numPerformed != 0){
var x = Math.floor(Math.random() * l.length);
l.splice(x, 0, l.shift())
numPerformed--;
}
return l
}
function test_order(i,j,l){ //PROBLEM IS IN HERE!!!!
var n = 0
var trials = 10
var count = 0
while (count < trials){ // PROBLEM IN WHILE LOOP
let arrayCopy = JSON.parse(JSON.stringify(l));
//console.log(arrayCopy)
var m = top_to_random(arrayCopy)
m.indexOf(i) < m.indexOf(j) ? n++ : n = n + 0
//console.log(arrayCopy)
console.log(m)
count++
}
var prob = n/trials
return prob
}
//Argument Inputs
var numCards = parseInt(prompt("Enter number of cards in deck: "))
var l = list(numCards)
var numPerformed = parseInt(prompt("Enter number of shuffles to perform on deck: "));
var i = parseInt(prompt("i: "))
var j = parseInt(prompt("j: "))
//Execution
console.log(test_order(i,j,l))
Problem is not where you think it is, it's in your top_to_random function. You count the number of mixes done in your shuffle down from numPerformed, but this is a global-scope variable, so its not reset at each call. You should pass the mix count as a parameter like this:
function top_to_random(l, mixNum){
for (;mixNum > 0; mixNum--) {
var x = Math.floor(Math.random() * l.length);
l.splice(x, 0, l.shift());
}
return l;
}
Fixing a number of your syntax miconstructs, I get this code:
function list(numCards){
var newList = [];
var i = 0;
while (i < numCards){
newList.push(i);
i++;
}
return newList;
}
function top_to_random(l, mixNum){
for (;mixNum > 0; mixNum--) {
var x = Math.floor(Math.random() * l.length);
l.splice(x, 0, l.shift());
}
return l;
}
function test_order(i,j,l){ //Problem is NOT in here
let n = 0;
let trials = 10;
for (let count = 0; count < trials; count++) { // No not here
let arrayCopy = [...l];
top_to_random(arrayCopy, numPerformed);
console.log(arrayCopy)
if (arrayCopy.indexOf(i) < arrayCopy.indexOf(j)) n++;
console.log(arrayCopy);
}
var prob = n/trials;
return prob;
}
// Argument Inputs
var numCards = parseInt(prompt("Enter number of cards in deck: "));
var l = list(numCards);
var numPerformed = parseInt(prompt("Enter number of shuffles to perform on deck: "));
var i = parseInt(prompt("i: "));
var j = parseInt(prompt("j: "));
//Execution
console.log(test_order(i,j,l));
Also You should be more careful about details when you code:
You have a lot of missing semicolons
You're mixing function arguments and global variables with no logic to the decision
Don't use while when you should be using for
Ternary operator to perform a simple if ?
You'd better use const and let instead of var. For one thing it would have saved you this error
Better written code:
const SHUFFLE_REPEATS = 10;
function list(numCards) {
const newList = [];
for (let i = 0; i < numCards; i++)
newList.push(i);
return newList;
}
function top_to_random(l, mixNum) {
for (; mixNum > 0; mixNum--) {
const x = Math.floor(Math.random() * l.length);
l.splice(x, 0, l.shift());
}
return l;
}
function test_order(i, j, l) {
let n = 0;
for (let count = 0; count < SHUFFLE_REPEATS; count++) {
const arrayCopy = [...l];
top_to_random(arrayCopy, numPerformed);
console.log(arrayCopy)
if (arrayCopy.indexOf(i) < arrayCopy.indexOf(j)) n++;
}
return n / SHUFFLE_REPEATS;
}
// Argument Inputs
const numCards = parseInt(prompt("Enter number of cards in deck: "));
const l = list(numCards);
const numPerformed = parseInt(prompt("Enter number of shuffles to perform on deck: "));
const i = parseInt(prompt("i: "));
const j = parseInt(prompt("j: "));
//Execution
console.log(test_order(i,j,l));

JavaScript algorithm question: get the find the contiguous subarray which has the largest sum from an array

The question originates from this leetcode question: https://leetcode.com/problems/maximum-subarray/
But instead of returning the largest sum, I want to return the subarray that has the largest sum. For example, [-2,1,-3,4,-1,2,1,-5,4], the largest sum is 6 as in [4,-1,2,1] . Here I want to return [4,-1,2,1] not 6 the number.
Here is my attempt:
var maxSubArray = function(nums) {
let max = -Infinity
let sum = 0
const results = []
for(const num of nums) {
results.push(num)
sum += num
max = Math.max(sum, max)
if(sum < 0) {
sum = 0
results.length = 0
}
}
return results
};
maxSubArray([-2,1,-3,4,-1,2,1,-5,4])
However it returns an incorrect answer - [ 4, -1, 2, 1, -5, 4 ]. I found it really hard to implement this since it is hard to determine whether or not we should keep adding the subsequent item in the results array.
Wondering if anyone would like to give it a try.
In this tutorial, by using Kadane’s algorithm and maintain indices whenever we get the maximum sum.
var maxSubArray = function(nums) {
var max_so_far = 0, max_ending_here = 0;
var startIndex = -1;
var endIndex = -1;
for(var i = 0; i < nums.length; i++) {
if (nums[i] > max_ending_here + nums[i]) {
startIndex = i;
max_ending_here = nums[i];
} else
max_ending_here = max_ending_here + nums[i];
if (max_so_far < max_ending_here) {
max_so_far = max_ending_here;
endIndex = i;
}
}
return nums.slice(startIndex, endIndex + 1);
};
console.log(maxSubArray([-2,1,-3,4,-1,2,1,-5,4]))
Thanks baeldung's blog.
This page shows how to maintain indices whenever we get the maximum sum.
No JS, so I copy Java code here:
static void maxSubArraySum(int a[], int size)
{
int max_so_far = Integer.MIN_VALUE,
max_ending_here = 0,start = 0,
end = 0, s = 0;
for (int i = 0; i < size; i++)
{
max_ending_here += a[i];
if (max_so_far < max_ending_here)
{
max_so_far = max_ending_here;
start = s;
end = i;
}
if (max_ending_here < 0)
{
max_ending_here = 0;
s = i + 1;
}
}
System.out.println("Maximum contiguous sum is "
+ max_so_far);
System.out.println("Starting index " + start);
System.out.println("Ending index " + end);
}

Find a subset of an array satisfying some condition

Suppose that an array of N numbers is given.
How to find a subset that its sum is multiple of N?
I want to know the best approach.
The recursive function would be the right choice, but stack overflow for large number N isn't allowed.
Here is my code, but it doesn't work.
const arr = [];
const TOTAL_NUM = 5;
let sum = 0;
for (let i = 0; i < TOTAL_NUM; i++) {
arr.push(parseInt(Math.random() * TOTAL_NUM) + 1);
sum += arr[i];
}
const mod = sum % TOTAL_NUM;
for (let i = 0; i < TOTAL_NUM; i++) {
let sum = arr[i]
let found = false;
for (let j = i + 1; j < TOTAL_NUM; j++) {
sum += arr[j];
if (sum % TOTAL_NUM === 0 || (sum - mod) % TOTAL_NUM === 0) {
found = true;
console.log('Sum = %d', sum);
break;
}
}
if (found) break;
}
We don't necessarily need to recurse. We can iterate on the known remainders so far.
JavaScript code below (this is exhaustive; we could have a more space efficient version to return just one subset by adjusting what we store):
// 'rem' stands for "remainder"
function f(A){
let N = A.length
let rems = {0: [[]]}
for (let a of A){
let newRems = {}
for (let rem in rems){
let newRem = (a + Number(rem)) % N
newRems[newRem] = (rems[newRem] || []).concat(
rems[rem].map(x => x.concat(a)))
}
newRems[a % N] = (rems[a % N] || []).concat([[a]])
rems = Object.assign(rems, newRems)
}
return rems[0].slice(1)
}
var A = [1, 6, 2, 3, 4]
console.log(JSON.stringify(A))
console.log(`N: ${A.length}`)
console.log(JSON.stringify(f(A)))
I want to answer my question and to be evaluated by audiences.
This is my current code. I'll explain.
Assume we have an array of N numbers.
In loop for variable i = 0, we get N subsets and its inner sums. If there is at least one subset that its sum is multiple of N, it will be a solution. If not, the value of (sum % N) would take one value between 1 and (N-1). There exist N sums and (N-1) possible remainders. Therefore, there exist at least one pair (n, m) that n-th sum and m-th sum would have the same remainder, where 0 < n < m < N.
In this case, the sum of a subset [arr[n+1], arr[n+2], ... arr[m]] would be the multiple of N. So we can find n and m to solve this problem.
Below is the code to find n and m.
const arr = [];
const TOTAL_NUM = 5;
for (let i = 0; i < TOTAL_NUM; i++) {
arr.push(parseInt(Math.random() * TOTAL_NUM * 10) + 1);
}
console.log(arr.join(', '));
// find n and m
for (let i = 0; i < TOTAL_NUM; i++) {
let sum = 0;
found = false;
for (let j = i; j < TOTAL_NUM; j++) {
sum += arr[j];
if (sum % TOTAL_NUM === 0) {
found = true;
// output result
console.log('Sum = %d, n = %d, m = %d', sum, i, j);
break;
}
}
if (found) break;
}
As you can see, this code requires N * (N-1) / 2 loop, and no memory. Even for very large N, it would take a few milliseconds to find n and m.
It took about 20~80ms to find a solution for N = 10000000 on my computer(Core i5 4460 # 2.90GHz).

Infinity loop with generating random numbers?

I'm working on a script that creates random mathematical problems (simple questions). The problem is that there seems to be an infinite loop, and I can't figure out where or how my script can run without this part of the code.
https://codepen.io/abooo/pen/GyJKwP?editors=1010
var arr = [];
var lastArr = [];
while(lastArr.length<122){
arr.push('<br>'+Math.round(Math.random() * 10)+'+'+Math.round(Math.random() * 10)+'=');
lastArr=removeDuplicates(arr);
}
document.write(lastArr.join(' '));
alert(arr.length);
function removeDuplicates(arr){
let unique_array = []
for(let i = 0;i < arr.length; i++){
if(unique_array.indexOf(arr[i]) == -1){
unique_array.push(arr[i])
}
}
return unique_array
}
This is the working snippet without any infinity loop.
var arr = [];
while(arr.length < 121){
var randValue = '<br>'+Math.round(Math.random() * 10)+'+'+Math.round(Math.random() * 10)+'='
arr.push();
// Check duplicate elements before push
if ( arr.indexOf(randValue) == -1 ) arr.push(randValue);
}
document.write(arr.join(' '));
alert(arr.length);
It looks like you are trying to shuffle every possible outcome of adding two numbers from 0 to 10. Why not do that, rather than your attempt of "throw missiles into pidgeonholes and hope for the best"?
function generateArray(maxA, maxB) {
var arr = [],
a, b;
for (a = 0; a <= maxA; a++) {
for (b = 0; b <= maxB; b++) {
arr.push([a, b]);
}
}
return arr;
}
function shuffleArray(arr) {
// simple Fisher-Yates shuffle, modifies original array
var l = arr.length,
i, j, t;
for (i = l - 1; i > 0; i--) {
j = Math.floor(Math.random() * (i + 1));
t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
function outputArray(arr) {
var i, l = arr.length;
for (i = 0; i < l; i++) {
document.write("<br />" + arr[i][0] + " + " + arr[i][1] + " = ");
}
}
var arr = generateArray(10, 10);
shuffleArray(arr);
outputArray(arr);
The line Math.round(Math.random() * 10) will give you 11 possible outcomes (from 0 to 10). That means there are 11*11 non-duplicates lastArr can hold.
As mentioned in the comments, it does not only take a long time for every possibility to occur, it is also impossible for lastArr to be longer than 121 (11*11), which means your loop cannot end, due to the condition while(lastArr.length<122).
Besides that there are better ways to achieve the desired result, changing your code to this will make it work:
var arr = [];
var lastArr = [];
while(lastArr.length<121){ // Here I change 122 to 121
arr.push('<br>'+Math.round(Math.random() * 10)+'+'+Math.round(Math.random() * 10)+'=');
lastArr=removeDuplicates(arr);
}
document.write(lastArr.join(' '));
alert(arr.length);
function removeDuplicates(arr){
let unique_array = []
for(let i = 0;i < arr.length; i++){
if(unique_array.indexOf(arr[i]) == -1){
unique_array.push(arr[i])
}
}
return unique_array
}

Categories

Resources