I am working through a two-sum problem where I pass in an unsorted array, and a target, k, and I return the the highest sum of any two numbers that are less than k. If there's no possible sum less than k, then return -1.
I think I am on the right path by sorting the array and then using a 2-pointer technique but I am stuck now. If my sum of numbers is greater than the target, then I decrement the end pointer...that seems definitive. The else though, I am not sure if I am doing correctly.
var twoSumLessThanK = function(nums, k) {
// [1,8,23,23,33,34,54,75] 60
nums.sort((a, b) => a - b)
let start = 0;
let end = 0;
let max = -1;
while (start < end) {
if (nums[start] + nums[end] >= k) {
end--
} else if (nums[start] + nums[end] < k) {
max = Math.max(max, nums[start] + nums[end])
start++
}
}
return max;
};
console.log(twoSumLessThanK([1,8,23,23,33,34,54,75], 60));
You could check the sum of two values and decrement the right index if greater or equal than k or store the sum, if greater than the max value and increment the left index.
1 8 23 23 33 34 54 75 sum max < 60
> < 76
> < 55 -> max
> < 62
> < 42
> < 57 -> max
> < 57
> < 67
const
twoSumLessThanK = function(nums, k) {
nums.sort((a, b) => a - b);
let left = 0,
right = nums.length -1,
max = -Number.MAX_VALUE;
while (left < right) {
let sum = nums[left] + nums[right];
if (sum >= k) {
right--;
continue;
}
if (max < sum) max = sum;
left++;
}
return max;
};
console.log(twoSumLessThanK([1, 8, 23, 23, 33, 34, 54, 75], 60));
An alternative could be a nested for loop, this way you do't have to handle start and end manually
const twoSumLessThanK = function(nums, k)
{
let max = -1;
const len = nums.length - 1
for (let start = 0; start < len; start++)
{
for (let end = len; end > start; end--)
{
if (nums[start] + nums[end] < k) max = Math.max(max, nums[start] + nums[end])
}
}
return max;
};
console.log(twoSumLessThanK([1,8,23,23,33,34,54,75], 60)); // Logs 57
A different option would be the following:
const twoSumLessThanK = function(nums, k)
{
nums.sort((a, b) => a - b)
let max = -1;
let greatest = null
while (nums.length > 1 && max < k - 1)
{
greatest = nums.pop()
for (let i = nums.length - 1; i >= 0; i--)
{
if (greatest + nums[i] < k)
{
max = Math.max(max, greatest + nums[i])
break
}
}
}
return max;
};
Or you can just fix your version if you want:
const twoSumLessThanK = function(nums, k)
{
// [1,8,23,23,33,34,54,75] 60
nums.sort((a, b) => a - b)
const len = nums.length - 1
let start = 0;
let max = -1;
let end = len;
while (start < len)
{
if (nums[start] + nums[end] < k)
{
max = Math.max(max, nums[start] + nums[end])
start++
end = len;
}
else end--
}
return max;
};
it wasn't so hard to code...?
const twoSumLessThanK = (nums, k) =>
{
let max = -1
, arr = nums.reduce((a,c)=> // decrase order values < k
{
if (c < k)
{
let p = a.findIndex(x=>x < c)
if (p<0) p = a.length
a.splice( p,0,c)
}
return a
}
,[])
;
if (arr.length<2) return max
for(i=arr.length;--i;)
for(j=i;j--;)
{
let sum = arr[i] + arr[j]
if (sum >= k && i === j+1) return max
if (sum < k && sum > max ) max = sum
}
return max
}
console.log(twoSumLessThanK([33,1,8,23,23,34,54,75], 60))
Related
I'm generating a number based on a fixed character set.
function generator()
{
var text = "";
var char_list = "LEDGJR", number_list = "0123456789";
for(var i=0; i < 2; i++ )
{
text += char_list.charAt(Math.floor(Math.random() * char_list.length));
}
for(var j=0; j < 2; j++ )
{
text += number_list.charAt(Math.floor(Math.random() *
number_list.length));
}
return text;
}
Result :
RE39, JE12 etc...
Once all the permutation related to the above sequence is done, then the generator should generate string as RE391, JE125 means adding one more number to the complete number.
How can I get the permutation count of sequence?
For simplicity consider the case where:
chars = "AB"
nums = "123";
and we want to generate a 4-digit sequence of two chars and two numbers.
We define these variables
rows = [chars, chars, nums, nums]
rowSizes = rows.map(row => row.length) // [2, 2, 3, 3]
It’s easy to see the set size of all possible permuations equals:
spaceSize = rowSizes.reduce((m, n) => m * n, 1) // 2*2*3*3 = 36
And we define two set of utility functions, usage of which I'll explain in detail later.
decodeIndex() which gives us uniqueness
function euclideanDivision(a, b) {
const remainder = a % b;
const quotient = (a - remainder) / b;
return [quotient, remainder]
}
function decodeIndex(index, rowSizes) {
const rowIndexes = []
let dividend = index
for (let i = 0; i < rowSizes.length; i++) {
const [quotient, remainder] = euclideanDivision(dividend, rowSizes[i])
rowIndexes[i] = remainder
dividend = quotient
}
return rowIndexes
}
getNextIndex() which gives us pseudo-randomness
function isPrime(n) {
if (n <= 1) return false;
if (n <= 3) return true;
if (n % 2 == 0 || n % 3 == 0) return false;
for (let i = 5; i * i <= n; i = i + 6) {
if (n % i == 0 || n % (i + 2) == 0) return false;
}
return true;
}
function findNextPrime(n) {
if (n <= 1) return 2;
let prime = n;
while (true) {
prime++;
if (isPrime(prime)) return prime;
}
}
function getIndexGeneratorParams(spaceSize) {
const N = spaceSize;
const Q = findNextPrime(Math.floor(2 * N / (1 + Math.sqrt(5))))
const firstIndex = Math.floor(Math.random() * spaceSize);
return [firstIndex, N, Q]
}
function getNextIndex(prevIndex, N, Q) {
return (prevIndex + Q) % N
}
Uniqueness
Like mentioned above, spaceSize is the number of all possible permutations, thus each index in range(0, spaceSize) uniquely maps to one permutation. decodeIndex helps with this mapping, you can get the corresponding permutation to an index by:
function getSequenceAtIndex(index) {
const tuple = decodeIndex(index, rowSizes)
return rows.map((row, i) => row[tuple[i]]).join('')
}
Pseudo-Randomness
(Credit to this question. I just port that code into JS.)
We get pseudo-randomness by polling a "full cycle iterator"†. The idea is simple:
have the indexes 0..35 layout in a circle, denote upperbound as N=36
decide a step size, denoted as Q (Q=23 in this case) given by this formula‡
Q = findNextPrime(Math.floor(2 * N / (1 + Math.sqrt(5))))
randomly decide a starting point, e.g. number 5
start generating seemingly random nextIndex from prevIndex, by
nextIndex = (prevIndex + Q) % N
So if we put 5 in we get (5 + 23) % 36 == 28. Put 28 in we get (28 + 23) % 36 == 15.
This process will go through every number in circle (jump back and forth among points on the circle), it will pick each number only once, without repeating. When we get back to our starting point 5, we know we've reach the end.
†: I'm not sure about this term, just quoting from this answer
‡: This formula only gives a nice step size that will make things look more "random", the only requirement for Q is it must be coprime to N
Full Solution
Now let's put all the pieces together. Run the snippet to see result.
I've also includes the a counter before each log. For your case with char_list="LEDGJR", number_list="0123456789", the spaceSize for 4-digit sequence should be 6*6*10*10 = 3600
You'll observe the log bump to 5-digit sequence at 3601 😉
function euclideanDivision(a, b) {
const remainder = a % b;
const quotient = (a - remainder) / b;
return [quotient, remainder];
}
function decodeIndex(index, rowSizes) {
const rowIndexes = [];
let divident = index;
for (let i = 0; i < rowSizes.length; i++) {
const [quotient, remainder] = euclideanDivision(divident, rowSizes[i]);
rowIndexes[i] = remainder;
divident = quotient;
}
return rowIndexes;
}
function isPrime(n) {
if (n <= 1) return false;
if (n <= 3) return true;
if (n % 2 == 0 || n % 3 == 0) return false;
for (let i = 5; i * i <= n; i = i + 6) {
if (n % i == 0 || n % (i + 2) == 0) return false;
}
return true;
}
function findNextPrime(n) {
if (n <= 1) return 2;
let prime = n;
while (true) {
prime++;
if (isPrime(prime)) return prime;
}
}
function getIndexGeneratorParams(spaceSize) {
const N = spaceSize;
const Q = findNextPrime(Math.floor((2 * N) / (1 + Math.sqrt(5))));
const firstIndex = Math.floor(Math.random() * spaceSize);
return [firstIndex, N, Q];
}
function getNextIndex(prevIndex, N, Q) {
return (prevIndex + Q) % N;
}
function generatorFactory(rows) {
const rowSizes = rows.map((row) => row.length);
function getSequenceAtIndex(index) {
const tuple = decodeIndex(index, rowSizes);
return rows.map((row, i) => row[tuple[i]]).join("");
}
const spaceSize = rowSizes.reduce((m, n) => m * n, 1);
const [firstIndex, N, Q] = getIndexGeneratorParams(spaceSize);
let currentIndex = firstIndex;
let exhausted = false;
function generator() {
if (exhausted) return null;
const sequence = getSequenceAtIndex(currentIndex);
currentIndex = getNextIndex(currentIndex, N, Q);
if (currentIndex === firstIndex) exhausted = true;
return sequence;
}
return generator;
}
function getRows(chars, nums, rowsOfChars, rowsOfNums) {
const rows = [];
while (rowsOfChars--) {
rows.push(chars);
}
while (rowsOfNums--) {
rows.push(nums);
}
return rows;
}
function autoRenewGeneratorFactory(chars, nums, initRowsOfChars, initRowsOfNums) {
let realGenerator;
let currentRowOfNums = initRowsOfNums;
function createRealGenerator() {
const rows = getRows(chars, nums, initRowsOfChars, currentRowOfNums);
const generator = generatorFactory(rows);
currentRowOfNums++;
return generator;
}
realGenerator = createRealGenerator();
function proxyGenerator() {
const sequence = realGenerator();
if (sequence === null) {
realGenerator = createRealGenerator();
return realGenerator();
} else {
return sequence;
}
}
return proxyGenerator;
}
function main() {
const char_list = "LEDGJR"
const number_list = "0123456789";
const generator = autoRenewGeneratorFactory(char_list, number_list, 2, 2);
let couter = 0
setInterval(() => {
console.log(++couter, generator())
}, 10);
}
main();
How to solve this giving undesired result, getting false always.
function isPelindrom(n) {
if (n < 0) return false;
let orgNum = n
let reversed = 0
for (let x = 0; x <= orgNum; x++) {
let lastDigit = orgNum % 10;
reversed = (reversed * 10) + lastDigit;
orgNum = parseInt(orgNum / 10);
}
return n == reversed
}
isPelindrom(12321)
function Palindrome(num) {
let numToStringArray = num.toString();
const reversed = numToStringArray.toString().split('').reverse().join('');
return numToStringArray === reversed ? "It's a palindrome" : "It's not a palindrome";
}
console.log(Palindrome(989));
console.log(Palindrome(23));
console.log(Palindrome(9));
function Palindrome(number) {
var temp = number, final = 0;
while (number > 0) {
rem = number % 10;
number = parseInt(number / 10);
final = final * 10 + rem;
}
if (temp == final) {
return "It's Palindrome";
}
else {
return "It's not Palindrome";
}
}
console.log(Palindrome(989));
console.log(Palindrome(23));
console.log(Palindrome(9));
You can change it to a for loop and either set it to greater or equal to 0.1 or just greater than 0.
function isPelindrom(n) {
if (n < 0) return false;
let orgNum = n
let reversed = 0
while(orgNum>=0.1) {
let lastDigit = orgNum % 10;
reversed = (reversed * 10) + lastDigit;
orgNum = parseInt(orgNum / 10);
}
return n == reversed
}
console.log(isPelindrom(12321))
console.log(isPelindrom(12322))
Does while loop count?
const isPalindrome = num => {
const origin = num
let reversed = 0
while (num !== 0) {
const digit = num % 10
reversed = reversed * 10 + digit
num = Math.floor(num / 10)
}
return origin === reversed
}
console.log(isPalindrome(12321))
console.log(isPalindrome(12331))
You can try this:
function isPelindrom(n) {
if (n < 0) return false;
let orgNum = n
let reversed = 0
var numberOfDigits = 0;
for(i = orgNum; i > 1; ++i){
++numberOfDigits;
i = Math.floor(i/10);
}
for (let x = 0; x < numberOfDigits; x++) {
let lastDigit = orgNum % 10;
reversed = (reversed * 10) + lastDigit;
orgNum = parseInt(orgNum / 10);
}
return n == reversed
}
I'm doing an exercise which i'm no being able to solve. I need to get the maximum accumulated profit by buying and selling bitcoins. I have a function(A,Y) which receive an A = array of different prices during time and a Y = fee
Restrictions:
Note: If a bitcoin was bought at 0 and sold at 1, we would have ad a loss of A[1] - A[0] =7050 -7200 - Y = -200. So, that movement was not made.
Note2: You can only have 1 bitcoin at the time. To sell, you have to have bought first. To buy, you need to have nothing or sold before.
Note3: Movements need to be time consequents. You cannot buy at A[5] and sell at A[4]
Note4: If no profit cannot be made, it should return 0
complexity is O(N)
A = [7200,7050,7300,7500,7440,7200,7300,7280,7400] //expected result 550
Y = 50
A[3] - A[1] - Y = 7500 - 7050 - 50 = 400
A[8] - A[5] - Y = 7400 - 7200 - 50 = 150
result = 550 //maximum accumulated profit
This is what i have
function solution(A, Y) {
if(A.length < 2) {
return 0;
}
var minIndex = (A[0] > A[1]) ? 1 : 0;
var minPrice = A[minIndex];
var acum = 0;
var i = minIndex + 1
for (i; i< A.length-1; i++) {
if( (A[i] - minPrice - Y) > (A[i+1] - minPrice - Y )) {
acum += A[i] - minPrice - Y;
i = i+1
} else {
acum += A[i + 1] - minPrice - Y;
i = i+2
}
minPrice = (A[i] > A[i+1]) ? A[i+1] : A[i];
}
return acum > 0 ? acum : 0;
}
Actually i'm getting 450 but it should be 550
It looks more complicated as it seems to be, because you need to check every single buying price with all possible selling price.
The result is a tree with this brute force approach.
This solution returns only the maximum profit with all buy/sell prices.
function maxima(array, fee) {
function iter(prices, index, count) {
var i = 0, profit = 0;
if (index >= array.length) {
if (!prices.length || prices.length % 2) {
return;
}
if (prices.some((v, i, a) => i && (i % 2 ? a[i - 1] >= v : a[i - 1] < v))) {
return;
}
while (i < prices.length) {
profit += prices[i + 1] - prices[i] - fee;
i += 2;
}
if (!result.length || result[0].profit < profit) {
result = [{ profit, prices }];
} else if (result[0].profit === profit) {
result.push({ profit, prices });
}
return;
}
iter(prices.concat(array[index]), index + 1); // buy/sell
iter(prices, index + 1); // no action
}
var result = [];
iter([], 0, 0);
return result;
}
console.log(maxima([7200, 7050, 7300, 7500, 7440, 7200, 7300, 7280, 7400], 50));
.as-console-wrapper { max-height: 100% !important; top: 0; }
I know you already have an answer, but I would like to propose a possible O(n) solution. The idea is that you monitor direction of price movement along with local min and max. You define a change in direction anytime the price changes direction by more than Y from the local min or max. You buy and sell on direction changes.
var A = [6000, 7200, 7050, 7040, 7045, 7041, 7039, 7300, 7500, 7490, 7480, 7501, 7440, 7200, 7300, 7280, 7400];
var A = [7200, 7050, 7300, 7500, 7440, 7200, 7300, 7280, 7400];
let Y = 50
function buysell(A, Y) {
let direction = -1
let min = A[0]
let max = 0
let total = 0
for (let i = 1; i < A.length; i++) {
if (direction == -1) {
if (A[i] < min) min = A[i]
if (A[i] - min > Y) { // only change direction if change is greater than Y
direction = 1;
max = A[i]
console.log('buy at', min)
}
} else { // price is going up
if (A[i] > max) max = A[i]
if (max - A[i] > Y) {
total += max - min - Y
console.log('sell at ', max)
min = A[i]
direction = -1
}
}
}
// buy at end if price was going up
if (direction == 1) {
console.log('sell at ', max)
total += max - min - Y
}
return total
}
console.log("total: ", buysell(A, Y))
// Test with some edge cases:
var A = [6000, 7200,7050, 7040, 7045, 7041, 7039,7040, 7300,7500, 7490, 7480,7501, 7440,7200,7300,7280,7400];
console.log("total: ", buysell(A, Y))
var A = [ 7172, 2477, 4755, 2297, 2893, 8863 ]
console.log("total: ", buysell(A, Y))
(I believe Mark_M's answer is the best here but I'll leave mine just for completeness.)
For each selling price we'd like to know the best buying price before it so we can pair that sale with the maximum accumulated before that. We can have an O(n^2) algorithm since we have to traverse back anyway.
function f(A, Y){
let m = [0].concat(new Array(A.length - 1));
for (let i=1; i<A.length; i++){
let smallest = A[i-1];
m[i] = m[i - 1];
for (let j=i-1; j>0; j--){
smallest = Math.min(smallest, A[j]);
if (smallest < A[i] + Y)
m[i] = Math.max(m[i], A[i] - smallest - Y + (m[j - 1] || 0));
}
}
return m[m.length - 1];
}
var a = [7200,7050,7300,7500,7440,7200,7300,7280,7400];
console.log(f(a, 50));
I was trying to find the prime factors of a number, recorded below as 'integer' using a for loop in javascript. I can't seem to get it working and I'm not sure whether it's my JavaScript or my calculation logic.
//integer is the value for which we are finding prime factors
var integer = 13195;
var primeArray = [];
//find divisors starting with 2
for (i = 2; i < integer/2; i++) {
if (integer % i == 0) {
//check if divisor is prime
for (var j = 2; j <= i / 2; j++) {
if (i % j == 0) {
isPrime = false;
} else {
isPrime = true;
}
}
//if divisor is prime
if (isPrime == true) {
//divide integer by prime factor & factor store in array primeArray
integer /= i
primeArray.push(i);
}
}
}
for (var k = 0; k < primeArray.length; k++) {
console.log(primeArray[k]);
}
The answer above is inefficient with O(N^2) complexity. Here is a better answer with O(N) complexity.
function primeFactors(n) {
const factors = [];
let divisor = 2;
while (n >= 2) {
if (n % divisor == 0) {
factors.push(divisor);
n = n / divisor;
} else {
divisor++;
}
}
return factors;
}
const randomNumber = Math.floor(Math.random() * 10000);
console.log('Prime factors of', randomNumber + ':', primeFactors(randomNumber).join(' '))
You can filter for duplicates as you please!
Here's a working solution:
function getPrimeFactors(integer) {
const primeArray = [];
let isPrime;
// Find divisors starting with 2
for (let i = 2; i <= integer; i++) {
if (integer % i !== 0) continue;
// Check if the divisor is a prime number
for (let j = 2; j <= i / 2; j++) {
isPrime = i % j !== 0;
}
if (!isPrime) continue;
// if the divisor is prime, divide integer with the number and store it in the array
integer /= i
primeArray.push(i);
}
return primeArray;
}
console.log(getPrimeFactors(13195).join(', '));
You were very much on the right track. There were two minor mistakes. The evaluation of integer - 1 seemed to be incorrect. I believe the more appropriate evaluation is <= integer in your outer for loop. This is because when you divide your integer below integer /= i, this results in the final integer evaluation to be 29. The final prime divisor in this case is also 29 and as such will need to be evaluated as <= as oppose to < integer - 1.
As for why the final log statement isn't working, there was a simple typo of primeArray[i] as oppose to primeArray[k].
I do believe there is a mistake in both code above. If you replace the integer by 100 the prime factorization won't work anymore as the factor 2 cannot be considered with those for loops. As j = 2, i = 2 and j<=i/2 in the condition - meaning the loop will never run for i=2, which is a prime factor.
Tried to make it work this way but couldn't figure out.
Had to rely on a different approach with a while loop here :
function getAllFactorsFor(remainder) {
var factors = [], i;
for (i = 2; i <= remainder; i++) {
while ((remainder % i) === 0) {
factors.push(i);
remainder /= i;
}
}
return factors;
}
https://jsfiddle.net/JamesOR/RC7SY/
You could also go with something like that :
let findPrimeFactors = (num) => {
let arr = [];
for ( var i = 2; i < num; i++) {
let isPrime
if (num % i === 0) {
isPrime = true;
for (var j = 2; j <= i; j++) {
if ( i % j === 0) {
isPrime == false;
}
}
}if (isPrime == true) { arr.push(i)}
}console.log(arr)
}
findPrimeFactors(543)
We can find the prime factor numbers up to n with only one loop. It is a very simple solution without any nested loop.
Time complexity would be less than O(n) because we are dividing "n" by "i".
function primeFactors(n) {
let arr=[];
let i = 2;
while(i<=n){
if(n%i == 0) {
n= n/i;
arr.push(i);
} else {
i++;
}
}
return arr;
}
// primeFactors(10) [2,5]
// primeFactors(10) [2,2,5,5]
// primeFactors(2700) [2, 2, 3, 3, 3, 5, 5]
When factorizing an integer (n) to its prime factors, after finding the first prime factor, the problem in hand is reduced to finding prime factorization of quotient (q).
Suppose n is divisible to prime p1 then we have n = p1 * q1 so after finding p1 the problem is reduced to factorizing q1 (quotient). If the function name is primeFactorizer then we can call it recursively and solution for n would be:
n = p1 * primeFactorizer(q1)
n = p1 * p2 * primeFactorizer(q2)
...
Until qn is prime itself.
Also I'm going to use a helper generator function which generates primes for us:
function * primes () {
let n = 2
while (true) {
let isPrime = true
for (let i = 2; i <= n / 2; i++) {
if (n % i === 0) {
isPrime = false
break
}
}
if (isPrime) {
yield n
}
n++
}
}
And function to factorize n would be:
function primeFactorizer (n, result = []) {
for (const p of primes()) {
if (n === p) {
result.push(p)
return result
}
if (n % p === 0) {
result.push(p)
return primeFactorizer(n / p, result)
}
}
}
I've refined this function over time, trying to get it as fast as possible (racing it against others' functions that I've found online, haven't found one that runs consistently faster than it yet).
function primFact(num) {
var factors = [];
/* since 2 is the only even prime, it's easier to factor it out
* separately from the odd factor loop (for loop doesn't need to
* check whether or not to add 1 or 2 to f).
* The condition is essentially checking if the number is even
* (bitwise "&" operator compares the bits of 2 numbers in binary
* and outputs a binary number with 1's where their digits are the
* same and 0's where they differ. In this case it only checks if
* the final digit for num in binary is 1, which would mean the
* number is odd, in which case the output would be 1, which is
* interpreted as true, otherwise the output will be 0, which is
* interpreted as false. "!" returns the opposite boolean, so this
* means that '!(num & 1)' is true when the num is not odd)
*/
while (!(num & 1)) {
factors.push(2);
num /= 2;
}
// 'f*f <= num' is faster than 'f <= Math.sqrt(num)'
for (var f = 3; f*f <= num; f += 2) {
while (!(num % f)) { // remainder of 'num / f' isn't 0
factors.push(f);
num /= f;
}
}
/* if the number is already prime, then this adds it to factors so
* an empty array isn't returned
*/
if (num != 1) {
factors.push(num);
}
return factors;
}
This performs very well at large numbers compared to functions I've run it against, especially when the number is prime, (rarely runs slower than 10ms when I've run it in an online compiler like OneCompiler) so if you want speed I'd say this is a pretty good way to go about it.
Still working on making it even faster, but only way to include all primes without adding new conditions to check is to iterate through all odd numbers.
I just started JavaScript but i managed to come up with my own solution for this while working on a school project with a similar objective.
Only issue is that it takes a very long time for large numbers, its not v ery efficient. But it works perfectly.
function isPrime(n){
if (n === 1){
return false;
}
else if (n === 2){
return true;
}
else{
for (let x = 2; x < n; x ++){
if (n % x === 0){
return false;
}
}
return true;
}
}
let primeFac = []
let num = 30
for (let x = 0; x <= num; x++){
if (num % x === 0 && isPrime(x) === true){
primeFac.push(x);
}
}
console.log(`${primeFac}`)
If you work up from the bottom there's no need to check if any following factor is prime. This is because any lower primes will have already been divided out.
function getPrimeFactorsFor(num) {
const primes = [];
for (let factor = 2; factor <= num; factor++) {
while ((num % factor) === 0) {
primes.push(factor);
num /= factor;
}
}
return primes;
}
console.log("10 has the primes: ", getPrimeFactorsFor(10));
console.log("8 has the primes: ", getPrimeFactorsFor(8));
console.log("105 has the primes: ", getPrimeFactorsFor(105))
console.log("1000 has the primes: ", getPrimeFactorsFor(1000))
console.log("1155 has the primes: ", getPrimeFactorsFor(1155))
In case somebody is looking for the fastest solution, here's one based on my library prime-lib. It can calculate prime factors for any number between 2 and 2^53 - 1, in under 1ms. The function source code is available here.
import {primeFactors} from 'prime-lib';
const factors = primeFactors(600851475143);
//=> [71, 839, 1471, 6857]
Here an other implementation to find prime factors, in three variations. It's more efficient than the other implementations, worst case sqrt(n), because it stops earlier.
The function* means it's a generator function. So a generator is returned instead of an array and the next prime factor is only calculated as soon as it is requested.
// Example: 24 -> 2, 3
function* singlePrimeFactors (n) {
for (var k = 2; k*k <= n; k++) {
if (n % k == 0) {
yield k
do {n /= k} while (n % k == 0)
}
}
if (n > 1) yield n
}
// Example: 24 -> 2, 2, 2, 3
function* repeatedPrimeFactors (n) {
for (var k = 2; k*k <= n; k++) {
while (n % k == 0) {
yield k
n /= k
}
}
if (n > 1) yield n
}
// Example: 24 -> {p: 2, m: 3}, {p: 3, m: 1}
function* countedPrimeFactors (n) {
for (var k = 2; k*k <= n; k++) {
if (n % k == 0) {
var count = 1
for (n /= k; n % k == 0; n /= k) count++
yield {p: k, m: count}
}
}
if (n > 1) yield {p: n, m: 1}
}
// Test code
for (var i=1; i<=100; i++) {
var single = JSON.stringify(Array.from(singlePrimeFactors(i)))
var repeated = JSON.stringify(Array.from(repeatedPrimeFactors(i)))
var counted = JSON.stringify(Array.from(countedPrimeFactors(i)))
console.log(i, single, repeated, counted)
}
// Iterating over a generator
for (var p of singlePrimeFactors(24)) {
console.log(p)
}
// Iterating over a generator, an other way
var g = singlePrimeFactors(24)
for (var r = g.next(); !r.done; r = g.next()) {
console.log(r.value);
}
My solution avoids returning not prime factors:
let result = [];
let i = 2;
let j = 2;
let number = n;
for (; i <= number; i++) {
let isPrime = number % i === 0;
if (isPrime) {
result.push(i);
number /= i;
}
while (isPrime) {
if (number % i === 0) {
result.push(i);
number /= i;
} else {
isPrime = false;
}
}
}
return result;
With so many good solutions above, wanted to make a little bit of improvement by using this theorem in the Math Forum Finding prime factors by taking the square root
.
function primeFactors(n)
{
// Print the number of 2s that divide n
while (n%2 == 0)
{
console.log(2);
n = n/2;
}
// n must be odd at this point. So we can skip
// one element (Note i = i +2)
for (var i = 3; i <= Math.sqrt(n); i = i+2)
{
// While i divides n, print i and divide n
while (n%i == 0)
{
console.log(i);
n = n/i;
}
}
// This condition is to handle the case when n
// is a prime number greater than 2
if (n > 2)
console.log(n);
}
primeFactors(344);
console.log("--------------");
primeFactors(4);
console.log("--------------");
primeFactors(10);
Hope this answer adds value.
Here is a solution using recursion
function primeFactors(num, primes){
let i = 2;
while(i < num){
if(num % i === 0){
primes.push(i);
return primeFactors(num/i, primes);
}
i++
}
primes.push(num);
return primes;
}
console.log(primeFactors(55, []))
console.log(primeFactors(15, []))
console.log(primeFactors(40, []))
console.log(primeFactors(13, []))
// [ 5, 11 ]
// [ 3, 5 ]
// [ 2, 2, 2, 5 ]
// [ 13 ]
I found this solution by chance when i was trying to simplify several
solutions that i saw here. Although it doesn't check if the divisor
is a prime number somehow it seems to work, i tested it with
miscellaneous numbers but i could not explain how this was possible.
function start() {
var integer = readInt("Enter number: ");
println("The prime factorization is: ");
for(var i = 2; i <= integer; i++) {
if (integer % i == 0) {
println(i);
integer = integer / i;
i = i - 1;
}
}
}
I checked the algorithm with yield, but that is a lot slower than recursive calls.
function rootnth(val, power=2) {
let o = 0n; // old approx value
let x = val;
let limit = 100;
let k = BigInt(power);
while(x**k!==k && x!==o && --limit) {
o=x;
x = ((k-1n)*x + val/x**(k-1n))/k;
}
return x;
}
// Example: 24 -> 2, 2, 2, 3
function repeatedPrimeFactors (n,list) {
if (arguments.length == 1) list = "";
if (n % 2n == 0) return repeatedPrimeFactors(n/2n, list + "*2")
else if (n % 3n == 0) return repeatedPrimeFactors(n/3n, list + "*3")
var sqrt = rootnth(n);
let k = 5n;
while (k <= sqrt) {
if (n % k == 0) return repeatedPrimeFactors(n/k, list + "*" + k)
if (n % (k+2n) == 0) return repeatedPrimeFactors(n/(k+2n), list + "*" + (k+2n))
k += 6n;
}
list = list + "*" + n;
return list;
}
var q = 11111111111111111n; // seventeen ones
var t = (new Date()).getTime();
var count = repeatedPrimeFactors(BigInt(q)).substr(1);
console.log(count);
console.log(("elapsed=" + (((new Date()).getTime())-t)+"ms");
Here I try for the factors 2 and 3, followed by alternatingly adding 2 anf 4 (5,7,11,13,17,...) until the square root of the number.
Seventeen ones (which is not prime) takes about 1 second and nineteen ones (which is prime) eight seconds (Firefox).
Here is the solution with the nested function using the filter method.
function primeFactors(params) {
function prime(number) {
for (let i = 2; i < number + 1; ) {
if (number === 2) {
return true;
}
if (number % i === 0 && number !== i) {
return false;
} else if (i < number) {
i++;
} else {
return true;
}
}
}
let containerPrime = [];
let containerUnPrime = [];
for (let i = 0; i < params; i++) {
if (prime(i)) {
containerPrime.push(i);
} else {
containerUnPrime.push(i);
}
}
return containerPrime.filter((e) => params % e === 0);
}
console.log(primeFactors(13195));
function primeFactorization(n) {
let factors = [];
while (n % 2 === 0) {
factors.push(2);
n = n / 2;
}
for (let i = 3; i <= Math.sqrt(n); i += 2) {
while (n % i === 0) {
factors.push(i);
n = n / i;
}
}
if (n > 2) {
factors.push(n);
}
return factors;
}
console.log(primeFactorization(100));
The answer with O(sqrt(n)) complexity, it's faster than O(n):
const number = 13195;
let divisor = 2;
const result = [];
let n = number;
while (divisor * divisor <= number) {
if (n % divisor === 0) {
result.push(divisor);
n /= divisor;
} else {
divisor++;
}
}
if (n > 1) {
result.push(n);
}
console.log(result);
The above code (the code which has while loop) is correct, but there is one small correction in that code.
var num, i, factorsArray = [];
function primeFactor(num) {
for (i = 2; i <= num; i++) {
while (num % i == 0) {
factorsArray.push(i);
num = num / 2;
}
}
}
primeFactor(18);
var newArray = Array.from(new Set(factorsArray));
document.write(newArray);
This is my solution
function prime(n) {
for (var i = 1; i <= n; i++) {
if (n%i===0) {
myFact.push(i);
var limit = Math.sqrt(i);
for (var j = 2; j < i; j++) {
if (i%j===0) {
var index = myFact.indexOf(i);
if (index > -1) {
myFact.splice(index, 1);
}
}
}
}
}
}
var n = 100, arr =[],primeNo = [],priFac=[];
for(i=0;i<=n;i++){
arr.push(true);
}
//console.log(arr)
let uplt = Math.sqrt(n)
for(j=2;j<=uplt;j++){
if(arr[j]){
for(k=j*j;k<=n;k+=j){
arr[k] = false;
}
}
}
for(l=2;l<=n;l++){
if(arr[l])
primeNo.push(l)
}
for(m=0;m<primeNo.length;m++){
if(n%primeNo[m]==0)
priFac.push(primeNo[m])
}
console.log(...priFac);
Assume we have an integer 16.
Is there a function, that returns random array of numbers, which compose its sum?
For example 7 1 2 4 1 1 or 1 5 2 3 6
I wonder if some elegant method of doing this in JavaScript exists.
No there's not existing function, but e.g.:
var n = 16;
var a = [];
while (n > 0) {
var s = Math.round(Math.random()*n);
a.push(s);
n -= s;
}
a contains the array.
you can consider this method too
function getRandomInt(max) {
return Math.floor(Math.random() * max + 1);
}
const total = 100;
const max = 20;
const nbrounds = 9;
function fillWithRandom(max, total, len) {
let arr = new Array();
let sum = 0;
newmax = max;
do {
newtotal = total - sum;
//max depending on length
console.log(arr.length,len);
if (arr.length+1 == len) {
arr.push(newtotal);
} else {
maxbylen = parseInt(newtotal / (len - arr.length));
// console.log('maxbylen', maxbylen, arr.length);
if (max > maxbylen) {
rndmax = max;
} else {
rndmax = maxbylen;
}
if (newtotal > max) {
rnd = getRandomInt(rndmax);
} else {
rnd = getRandomInt(newtotal);
}
arr.push(rnd);
}
sum = arr.reduce((acc, val) => acc + val, 0);
// console.log('sum', sum, 'newtotal', newtotal, 'rnd', rnd, arr);
} while (sum < total);
// console.log(arr);
//random order
return arr.map((value) => ({value, sort: Math.random()})).sort((a, b) => a.sort - b.sort).map(({ value }) => value);
}
;
console.log(fillWithRandom(max, total, nbrounds));