Solving the seventh with O(n) - javascript

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

Related

Last stone weight 2 in javascript, 1d array

last stone weight 2 solution in cpp
This is able to pass all test cases.
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int n = stones.size();
int total = 0;
for(int i = 0; i < n; i++){
total += stones[i];
}
int req = total / 2;
vector <bool> dp(req + 1, false);
dp[0] = true;
int reach = 0;
for(int i = 0; i < n; i++){
for(int j = req; j - stones[i] >= 0; j--){
dp[j] = dp[j] || dp[j - stones[i]];
if(dp[j]) reach = max(reach, j);
}
}
return total - (2 * reach);
}
};
I tried to replicate it in javascript and not able to pass
a simple test cases like [2,7,4,1,8,1]
Here is my attempt
var lastStoneWeightII = function(st) {
// stone #
const n = st.length;
// sum up
const sum = st.reduce((acc, curr) => {return acc+curr});
// e.g. half
const ha = Math.floor(sum / 2);
// half+1
const dp = Array(ha+1).fill(false);
// 1st ele = true
dp[0] = true;
// store tmp_max
let max = 0;
// loop element
for(let i=0; i<n; i++) {
// single element
const w = n[i];
// backward, half
for(let j=ha; j-w>=0; j--) {
// update condi
dp[j] = dp[j] || dp[j-w];
// never comes in
if(dp[j]) {
//test
console.log('++++ max', max, 'j', j)
max = Math.max(max, j);
}
}
}
return (sum - max) - max;
}

How to calculate what is probability of getting same result 8 times in a row, when flipping coin 1000 times?

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)

How to find the biggest prime number

I'm trying to solve a problem on an educational website platform.
This is the task/problem:
Write a program that finds and prints the biggest prime number which is <= N.
Input
On the first line you will receive the number N
Output
Print the biggest prime number which is <= N
Constraints
2 <= N <= 10 000 000
Examples
If N=13, then the biggest prime number is also 13.
If N=126, then the biggest prime number is also 113.
If N=26, then the biggest prime number is also 23
This is my code, which works fine, but the system does not accept it as fully correct because my code is slow/exceeds the memory limit:
const inputnumber = theNumberN; // Comes dymanically from the system
function getPrimes(max) {
let sieve = [];
let primes = [];
for (let i = 2; i <= max; ++i) {
if (!sieve[i]) {
primes.push(i);
for (let j = i << 1; j <= max; j += i) {
sieve[j] = true;
}
}
}
return primes;
}
let result = getPrimes(inputnumber);
let biggest = Math.max(...result);
console.log(biggest);
So, how can this be solved?
Can you offer a faster logic/algorithm
Assuming you are looking for only the biggest prime in a given range (2 <= N <= 10 000 000), the "simple" approach might actually be faster, since spread in primes below 10 000 000 is preety low (hence, the i-loop won't do so many rotations, disclaimer: this will not necessarly be true for all ranges).
function getBiggestPrime(max) {
let sieve = [];
let primes = [];
for (let i = 2; i <= max; ++i) {
if (!sieve[i]) {
primes.push(i);
for (let j = i << 1; j <= max; j += i) {
sieve[j] = true;
}
}
}
return primes[primes.length - 1];
}
function getBiggestPrimeTwo(max){
let biggestPrime = 1;
for (let i = max; i >= 2; i--){
let isPrime = true;
for (let j = 2; j < i; j++){
if (i % j == 0){ //break the loop, the number is not a prime
isPrime = false;
break;
}
}
if (isPrime){
biggestPrime = i;
break;
}
}
return biggestPrime;
}
function runTests(val, times){
var t0, t1, res, testStep;
testStep = val / times;
t0 = performance.now();
for (let i = 1; i <= times; i++){
res = getBiggestPrime(testStep*i);
}
t1 = performance.now();
console.log("Test1: " + res + ", took: " + (t1-t0) + "msec");
t0 = performance.now();
for (let i = 1; i <= times; i++){
res = getBiggestPrimeTwo(testStep*i);
}
t1 = performance.now();
console.log("Test2: " + res + ", took: " + (t1-t0) + "msec");
}
runTests(10000000, 50);

Optimal verification if a number is Palindrom in JS

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

Strange performance quirk in javascript

I experience a strange differences in performance of simple task depending of array I am working with. The task is to calculate sum of those elements in array which are greater than 5. Task is performed on arrays with equal lenghts.
I try the very same approach on three different array objects:
1) var hugeArray1 - array with all elemenets randomly picked from 0:10 range
2) var hugeArray2 - copy of hugeArray1 sorted with Array.prototype.sort()
3) var hugeArray3 - handcrafted but sorted array with values from 0:10 range, spread to equaly cover this interval.
I try to calculate sum of elements greater than 5 many times for each Array and then average them. What is strange, time needed varies a lot for those three arrays.
1) hugeArray1: 5.805ms
2) hugeArray2: 15.738ms
3) hugeArray3: 3.753ms
Result for array sorted with sort() is extreamly poor. Why is that? it looks like sort() returns some kind of wraper/proxy instead of 'native' Array, which affects performance. I tried it on 2 computers. Also i tried to change order of testing.
I include code below, please tell me what is happening here.
// random array with elements 0-10 of size n
function randomArray(n) {
var arr = [];
for (var i = 0; i < n; ++i) {
arr.push(Math.random() * 10);
}
return arr;
};
// measures time of execution
function measureTime(f) {
var start = new Date().getTime();
f();
var stop = new Date().getTime();
return stop - start;
};
// enumerate ofer array and calculate sum of elementsgreater than 5
function sumGreaterThan5(arr) {
var sum = 0;
for (var i = 0; i < arr.length; ++i) {
if (arr[i] > 5.0)
sum += arr[i];
}
return sum;
}
// generate array os size 'size' with elements with constant step to fill interval 0:10
function generateSortedArr(size) {
var arr = [];
for (var i = 0; i < size; ++i) {
arr.push(i * 10 / size);
}
return arr;
}
var huge = 1000000;
var hugeArray1 = randomArray(huge);
var hugeArray2 = hugeArray1.slice(0).sort();
var hugeArray3 = generateSortedArr(huge);
var hugeArrays = [hugeArray1, hugeArray2, hugeArray3];
hugeArrays.forEach(x=> {
var res = [];
for (var i = 0; i < 1000; ++i) {
res.push(measureTime(function () {
sumGreaterThan5(x);
}));
}
console.log(res.reduce((prev, curr)=> prev + curr) / res.length);
});
// random array with elements 0-10 of size n
function randomArray(n) {
var arr = [];
for (var i = 0; i < n; ++i) {
arr.push(Math.random() * 10);
}
return arr;
};
// measures time of execution
function measureTime(f) {
var start = new Date().getTime();
f();
var stop = new Date().getTime();
return stop - start;
};
// enumerate ofer array and calculate sum of elementsgreater than 5
function sumGreaterThan5(arr) {
var sum = 0;
for (var i = 0; i < arr.length; ++i) {
if (arr[i] > 5.0)
sum += arr[i];
}
return sum;
}
// generate array os size 'size' with elements with constant step to fill interval 0:10
function generateSortedArr(size) {
var arr = [];
for (var i = 0; i < size; ++i) {
arr.push(i * 10 / size);
}
return arr;
}
var huge = 1000000;
var hugeArray1 = randomArray(huge);
var hugeArray2 = hugeArray1.slice(0).sort();
var hugeArray3 = generateSortedArr(huge);
var hugeArrays = [hugeArray1, hugeArray2, hugeArray3];
hugeArrays.forEach(function(x){
var res = [];
for (var i = 0; i < 1000; ++i) {
res.push(measureTime(function () {
sumGreaterThan5(x);
}));
}
console.log(res.reduce(function(prev, curr){return prev + curr},0) / res.length);
});

Categories