Skip to content

Commit 78a9775

Browse files
committed
Create 266.js
1 parent 18885b3 commit 78a9775

File tree

1 file changed

+129
-0
lines changed

1 file changed

+129
-0
lines changed

266.js

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/* Part 1: Generate prime numbers below 190: */
2+
3+
const primeNumbersBelow190 = [];
4+
5+
for (let i = 2; i <= 190; i++) {
6+
let isPrime = true;
7+
8+
//since every composite number must have a prime factor less than or equal to its square root...
9+
for (let j = 0; j < primeNumbersBelow190.length; j++) {
10+
if (i % primeNumbersBelow190[j] === 0) {
11+
isPrime = false;
12+
break;
13+
}
14+
15+
if (primeNumbersBelow190[j] > Math.floor(Math.sqrt(i))) {
16+
break;
17+
}
18+
}
19+
20+
if (isPrime) {
21+
primeNumbersBelow190.push(i);
22+
}
23+
}
24+
25+
/* Part 2: Finding the PSR (Psuedo Square Root) */
26+
/*
27+
The pseudo square root of n is defined as the LARGEST divisor of n that doesn't exceed sqrt(n)
28+
The pseudo square root of the product of all the primes below 190 is thus going to be a number composed of primes below 190 (with each prime occuring exactly once) such that it doesnot exceed sqrt(n)
29+
30+
To make calculations easier, we can log everything, remembering our log properties:
31+
log(ab) = log(a) + log(b)
32+
and
33+
log(a^b) = b*log(a)
34+
*/
35+
36+
const logOfPrimeNumbersBelow190 = [];
37+
38+
primeNumbersBelow190.forEach(p => {
39+
logOfPrimeNumbersBelow190.push(Math.log(p));
40+
});
41+
42+
//our "target" is going to be the log of the square root of the product of all the prime numbers below 190, which we can find by summing the array and dividing by 2, based on log properties
43+
const target = 0.5 * logOfPrimeNumbersBelow190.reduce((accumulator, element) => {
44+
return (accumulator + element)
45+
});
46+
47+
//we now want to find the subset of logOfPrimeNumbersBelow190 that has a sum closest to target without going over it
48+
//Instead of brute forcing and testing all subsets, we can use the Meet in the Middle algorithm
49+
50+
let firstHalf = logOfPrimeNumbersBelow190.slice(0, Math.floor(logOfPrimeNumbersBelow190.length/2));
51+
let secondHalf = logOfPrimeNumbersBelow190.slice(Math.floor(logOfPrimeNumbersBelow190.length/2), logOfPrimeNumbersBelow190.length);
52+
53+
//helper function to return an array of objects containing attributes subset and sum, containing all possible subsets of an inputted array
54+
function subsetSums(arr) {
55+
let subsets = [[]];
56+
let result = [];
57+
58+
//iterate through items in the array
59+
for (let i = 0; i < arr.length; i++) {
60+
let currentSubsets = subsets.slice(); //create a temporary copy of subsets
61+
62+
for (let j = 0; j < currentSubsets.length; j++) {
63+
let newSubset = currentSubsets[j].concat(arr[i]); //add the current element to each existing subset to make new subsets and then add the new subsets to the array of subsets
64+
subsets.push(newSubset);
65+
}
66+
}
67+
68+
//sum all the subsets
69+
subsets.forEach((subset) => {
70+
let sum = subset.reduce((accumulator, element) => {
71+
return (accumulator + element)
72+
}, 0);
73+
74+
result.push({
75+
subset: subset,
76+
sum: sum
77+
});
78+
});
79+
80+
return result;
81+
}
82+
83+
const firstHalfSums = subsetSums(firstHalf);
84+
const secondHalfSums = subsetSums(secondHalf);
85+
86+
//sort them in ascending order
87+
firstHalfSums.sort((a, b) => a.sum - b.sum);
88+
secondHalfSums.sort((a, b) => a.sum - b.sum);
89+
90+
let firstHalfIterator = 0;
91+
let secondHalfIterator = secondHalfSums.length - 1;
92+
93+
let closestSumFoundSoFar = {
94+
sum: -Infinity,
95+
firstHalfIterator: null,
96+
secondHalfIterator: null
97+
};
98+
99+
//iterate through the 2 arrays, starting at the beginning of the first one and at the end of the first one
100+
while ((firstHalfIterator < firstHalfSums.length-1) && (secondHalfIterator > 0)) {
101+
let sum = firstHalfSums[firstHalfIterator].sum + secondHalfSums[secondHalfIterator].sum;
102+
103+
//if the sum of the current pair is too high, decrement the secondHalfIterator, so the sum gets lower
104+
if (sum > target) {
105+
secondHalfIterator--;
106+
} else { //otherwise, if the sum is greater than the closestSumFoundSoFar, update the object
107+
if (sum > closestSumFoundSoFar.sum) {
108+
closestSumFoundSoFar.sum = sum;
109+
closestSumFoundSoFar.firstHalfIterator = firstHalfIterator;
110+
closestSumFoundSoFar.secondHalfIterator = secondHalfIterator;
111+
}
112+
113+
firstHalfIterator++; //and increase the firstHalfIterator in hopes of finding an even larger sum that's smaller than the target
114+
}
115+
}
116+
117+
//the hard part's over, we now have the logarithms of the prime numbers whose sum is the closest to the target value
118+
let logarithmsOfPrimesWeWant = firstHalfSums[closestSumFoundSoFar.firstHalfIterator].subset.concat(secondHalfSums[closestSumFoundSoFar.secondHalfIterator].subset);
119+
120+
//raise e to the power of the logarithms to undo the logs, and then round it just to make up for rounding errors when we first took the logarithm
121+
let primesWeWanted = logarithmsOfPrimesWeWant.map((x) => Math.round(Math.exp(x)));
122+
123+
//we should now have an array of the prime numbers whose product is the pseudo square root of the product of all the primes below 190
124+
console.log(primesWeWanted);
125+
126+
//take the product of all the prime numbers in the primesWeWanted array, and mod it 10^16 each time we multiply another number with the accumulator
127+
let answer = primesWeWanted.reduce((accumulator, currentValue) => ((accumulator * BigInt(currentValue)) % (10n**16n)), 1n);
128+
129+
console.log(answer.toString()); //our answer!!

0 commit comments

Comments
 (0)