Find all possible combinations which make a specific number JavaScript - javascript

My problem is I have a number for example 17; I also have three other constant numbers: 2, 5, 7;
I need to find all possible combinations which make the specific number 17 or any other number;
5 + 5 + 7 = 17 (1 combination)
5 + 5 + 5 + 2 = 17 (2 combinations)
2 + 2 + 2 + 2 + 2 + 7 = 17 (3 combinations)
2 + 2 + 2 + 2 + 2 + 2 + 5 = 17 (4 combinations)
So the answer is 4.
I created my script which working correctly with the number 17 but wrong with bigger numbers as 20 or 30. How to make it working with all numbers ?
const seek = 30;
const firstNum = 2;
const secondNum = 5;
const thirdNum = 7;
let combinations = 0;
const maxDivisor = Math.round(seek / 2);
for (let i = 1; i <= maxDivisor; i += 1) {
if (secondNum * i + thirdNum === seek) {
combinations++
} else if (secondNum * i + firstNum === seek) {
combinations++
} else if (firstNum * i + secondNum === seek) {
combinations++
} else if (firstNum * i + thirdNum === seek) {
combinations++
} else if (thirdNum * i + firstNum === seek || thirdNum * i + secondNum === 0) {
combinations++
} else if (firstNum + secondNum + thirdNum === seek) {
combinations++
} else if (firstNum * i === seek || thirdNum * i === seek || secondNum * i === seek) {
combinations++
}
}
console.log(combinations);

Simple solution is to first calculate max multipliers for each number and then keep summing all the possible combinations.
/** LOGIC **/
function getCombinations(inputNumber, pieceNumbers) {
const combinations = []
const initial = maxes(inputNumber, pieceNumbers);
let divs = initial;
const sum = createSum(pieceNumbers);
while (!allZeros(divs)) {
if (sum(divs) === inputNumber) {
combinations.push(divs);
}
divs = decrement(divs, initial);
}
return combinations;
}
/**
* returns max multiplier for each number
* that is less than input number
* ie. for [2, 5] and input 17
* you get [8 (17 / 2); 3 (17 / 5)]
*/
function maxes(inputNumber, pieceNumbers) {
return pieceNumbers.map((num, i) =>
inputNumber / num | 0
)
}
/**
* decrements list of numbers till it contains only zeros
* if we have divs [2, 0] and initial [2, 5] the result
* will be [1, 5]
*/
function decrement(divs, initial) {
const arr = divs.slice();
let i = arr.length;
while (i--) {
if (arr[i] > 0) {
return [...arr.slice(0, i), arr[i] - 1, ...initial.slice(i + 1)];
}
}
}
function allZeros(divs) {
return divs.every(div => div === 0);
}
function createSum(pieceNumbers) {
return (divs) => divs.reduce((acc, itm, i) => acc + itm * pieceNumbers[i], 0);
}
function toPrint(combinations, pieceNumbers) {
const printable = combinations.map(nums =>
nums.map(
(n, i) => Array(n).fill(pieceNumbers[i]).join(" + ")
)
.filter(x => x)
.join(" + ")
).join("\n");
return printable;
}
/** VIEW **/
const addPieceEl = document.querySelector(".js-add-piece-number");
const removePieceEl = document.querySelector(".js-remove-piece-number");
const calculateEl = document.querySelector(".js-calculate");
const displayEl = document.querySelector(".js-display-result");
addPieceEl.addEventListener("click", () => {
addPieceEl.insertAdjacentHTML("beforebegin", ` <input type="number" class="js-piece-number number" value="7" /> `)
})
removePieceEl.addEventListener("click", () => {
addPieceEl.previousElementSibling.remove()
})
calculateEl.addEventListener("click", () => {
const inputNumber = Number(document.querySelector(".js-input-number").value);
const pieceNumbers = Array.from(document.querySelectorAll(".js-piece-number")).map(el => Number(el.value))
const combinations = getCombinations(inputNumber, pieceNumbers);
const total = `There are ${combinations.length} combinations for ${inputNumber} with ${pieceNumbers.join(", ")}:\n`;
displayEl.textContent = total + toPrint(combinations, pieceNumbers);
});
.number {
width: 30px;
}
Input Number: <input type="number" class="js-input-number number" value="17"/>
<br/>
<br/>
Piece Numbers:
<input type="number" class="js-piece-number number" value="2"/>
<input type="number" class="js-piece-number number" value="5"/>
<input type="number" class="js-piece-number number" value="7"/>
<button class="js-add-piece-number">+</button>
<button class="js-remove-piece-number">-</button>
<br/>
<br/>
<button class="js-calculate">calculate</button>
<pre class="js-display-result"/>

You can test all combinations
const n = 30;
console.log('Number to reach: n = ' + n);
const k = [7, 5, 2];
console.log('Numbers to use: k = ' + k);
console.log('n can be wrote: n = a*k[0] + b*k[1] + c*k[2]');
console.log('Let\'s found all combinations of [a, b, c]');
let t = [];
for (let a = 0; n >= a*k[0]; a++)
for (let b = 0; n >= a*k[0] + b*k[1]; b++)
for (let c = 0; n >= a*k[0] + b*k[1] + c*k[2]; c++)
if (n == a*k[0] + b*k[1] + c*k[2])
t.push([a, b, c]);
console.log('Number of combinations: ' + t.length);
for (let i = 0; i < t.length; i++)
console.log(
n + ' = ' + new Array()
.concat(new Array(t[i][0]).fill(k[0]).join(' + '))
.concat(new Array(t[i][1]).fill(k[1]).join(' + '))
.concat(new Array(t[i][2]).fill(k[2]).join(' + '))
.filter(e => e.length > 0)
.join(' + ')
);

I am assuming you only want solutions that are unique in the sense that 2+5 and 5+2 aren't unique.
Using recursion you can create an algorithm that can solve this problem for every number and every list of constants.
const seek = 17;
const numbs = [2,5,7];
const minNum = Math.min(...numbs);
let numberOfCombinations = 0;
seekCombinations(seek, numbs);
function seekCombinations (toSeek, numbs) {
for (let i = 0; i < numbs.length; i++) {
let newToSeek = toSeek - numbs[i];
if (newToSeek === 0) { //you found a combination
numberOfCombinations++;
} else if (newToSeek >= minNum) { //The new number to seek can still form a combination
//remove numbers from your list of constants that are smaller then then the number that is already in your current combination so you'll only get unique solutions.
let index = numbs.indexOf(numbs[i]);
let newNumbs = numbs.slice(index, numbs.length);
//recursively call seekCombinations
seekCombinations (newToSeek, newNumbs, currentCombination)
}
}
}

so whats the question?
whats wrong with your script or how to do it?
in case you missed it,
multiplying the number with i doesnt solve this problem. because:
30 = 2 + 2 + 5 + 7 + 7 + 7
30 = 2 + 2 + 2 + 5 + 5 + 7 + 7
any number of one of those 3 constants can appear there.
these cases are not covered by your script

Related

find all possible combinations of two integers

Each time I can climb 1 or 2 steps to reach the top (3 steps for example)
1 + 1 + 1, 1 + 2, 2 + 1. There are three cases (scenarios). Here's my voodoo code (the thing is some numbers (missing) don't appear for n = 5 it's 1211. the solution would be to do the reverse string and store two versions of such strings in the hash, so duplicates will disappear and after the cycle sums them.
function setCharAt(str, index, chr) {
if (index > str.length - 1) return str;
return str.substring(0, index) + chr + str.substring(index + 1);
}
let n = 9;
find(n);
function find(n) {
let origin = n; //every loop n decreases by one when it 0 while returns false,
let sum = 1;
n -= 1; //because n once once of 1's (n = 5) 1+1+1+1+1 then 1111, 1112 etc.
if (n <= 1) return sum;
while (origin <= n * 2) { //if n = 10; only"22222" can give 10, we don't go deeper
let str = "1".repeat(n); //from "1" of n(4) to "1111"
let copyStr = str;
while (str.length === copyStr.length) { //at the end we get 2222 then 22221,
// therefore the length will change, we exit the loop
let s = str.split('').reduce((a, b) => Number(a) + Number(b), 0); //countinng elems
console.log(str, "=", s);
if (s === origin) ++sum; //if elems equals the target we increase the amount by one
let one = str.lastIndexOf("1");
let two = str.lastIndexOf("2");
if (str[one] === "1" && str[one + 1] === "2") {
str = setCharAt(str, one, "2");
str = setCharAt(str, one + 1, "1");
} else {
str = setCharAt(str, one, "2");
}
}
--n;
}
console.log(sum)
}
If i understood your question, you wanna for let say n = 5 get all combinations of 1 and 2 (when you sum it) that give a sum of 5 (11111, 1112, etc)?
It is most likely that you wanna use recursion in these kind of situations, because its much easier. If you have just two values (1 and 2) you can achieve this pretty easily:
getAllCombinations = (n = 1) => {
const combinations = [];
const recursion = (n, sum = 0, str = "") => {
if (sum > n) return;
if (sum === n) {
combinations.push(str);
return;
}
// Add 1 to sum
recursion(n, sum + 1, str + "1");
// Add 2 to sum
recursion(n, sum + 2, str + "2");
};
recursion(n);
return combinations;
};

How to make single digits?

function SingleDigits(num) {
function makeDigits(num) {
let value = 1
let arr = String(num)
for(let i = 0 ; i < arr.length; i++){
value = value * Number(arr[i])
}
return value;
}
value += "";
while(1>=value.length){
let result = 1;
result = result
}
I'm going to do it until I make a single digit..
num = 786
7 * 8 * 6 -> 336
3 * 3 * 6 -> 54
5 * 4 -> 20
2 * 0 -> 0
like that.. how can i setting ?? or , my direction is right ?
You can use recursion to keep on going until the total equals 0.
eg.
function digits(num) {
const nums = num.toString().
split('').map(Number);
const total = nums.reduce(
(a,v) => a * v);
console.log(
nums.join(' * ') +
" => " + total);
if (total > 9)
digits(total);
}
digits(786);
Use recursion. The function can be pretty simple using a reducer to calculate the products.
const singleDigit = num => {
const nums = [...`${num}`];
const product = nums.reduce( (acc, val) => acc * +val, 1);
console.log(`${nums.join(" * ")} -> ${product}`);
return product <= 9 ? product : singleDigit(product);
}
console.log(singleDigit(4328));
You Should use recursive strategy.
function SingleDigits(num) {
if (parseInt(num / 10) > 0) {
let t = 1;
while (num > 0) {
t *= num % 10;
num = parseInt(num / 10);
}
console.log(t);
SingleDigits(t);
}
}
SingleDigits(786);
I am not sure why you have to use string here. You can do the following,
function SingleDigits(num) {
if(num <= 9) {
return num;
}
let res = 1;
while(num) {
res = res * (num % 10);
num = parseInt(num / 10);
}
if(res <= 9) {
return res;
}
return SingleDigits(res);
}
console.log(SingleDigits(786));

if a positive number is equal to its reverse

I'm making a program to receive a positive number and output "yes" if it's equal to its reverse;
otherwise, output "no".
What I've done so far:
HTML
<div class="column1">
<div class="input">
<button onclick="problem()"> Run the program </button>
</div>
<strong><p id="output"> </p></strong>
</div>
JS
function problem() {
var outputObj = document.getElementById("output");
var a = parseInt(prompt("Please enter a number: ", ""));
outputObj.innerHTML = "number: " + a + "<br><br>";
var reverse = 0;
while (a > 0){
num = a % 10; // the last digit
reverse = (reverse *10) + num; // calculating the reverse
a = Math.floor(a / 10); // go to next digit
}
if ( reverse == a){
outputObj.innerHTML = "yes";
}
else {
outputObj.innerHTML = "no";
}
outputObj.innerHTML = outputObj.innerHTML + "<br><br>" + "program ended";
document.getElementsByTagName("button")[0].setAttribute("disabled","true");
}
function isPalindrome(number){
return +number.toString().split("").reverse().join("") === number
}
Art for art
function palindrom(x)
{
let len = Math.floor(Math.log(x)/Math.log(10) +1);
while(len > 0) {
let last = Math.abs(x - Math.floor(x/10)*10);
let first = Math.floor(x / Math.pow(10, len -1));
if(first != last){
return false;
}
x -= Math.pow(10, len-1) * first ;
x = Math.floor(x/10);
len -= 2;
}
return true;
}
You should search for plaindromic numbers. For example the following code:
const isPalindrome = x => {
if (x < 0) return false
let reversed = 0, y = x
while (y > 0) {
const lastDigit = y % 10
reversed = (reversed * 10) + lastDigit
y = (y / 10) | 0
}
return x === reversed
}
const isPalindrome = num => {
const len = Math.floor(Math.log10(num));
let sum = 0;
for(let k = 0; k <= len; k++) {
sum += (Math.floor(num / 10 ** k) % 10) * 10 ** (len - k);
}
return sum === num;
}
console.log(isPalindrome(12321));

find sum of multiples 3 and 5, JS

I'm given a number and I need to find the sum of the multiples of 3 and 5 below the number.
For example:
20 => 78 = 3 + 5 + 6 + 9 + 10 + 12 + 15 + 18
My code works, but not for numbers greater than 1,000,000 (I tested it for 100,000 - it gives the result with 2sec delay). So, it should be optimized. Could someone help me? Why is my code slow? Thanks.
My logic is as follows:
add multiples to an array
filter duplicate values
sum all values
my code:
function sumOfMultiples(number) {
let numberBelow = number - 1;
let numberOfThrees = Math.floor(numberBelow / 3);
let numberOfFives = Math.floor(numberBelow / 5);
let multiples = [];
let multipleOfThree = 0;
let multipleOfFive = 0;
for (var i = 0; i < numberOfThrees; i++) {
multiples.push(multipleOfThree += 3);
}
for (var j = 0; j < numberOfFives; j++) {
multiples.push(multipleOfFive += 5);
}
return multiples
.filter((item, index) => multiples.indexOf(item) === index)
.reduce((a, b) => a + b);
}
You can also do this without using any loops.
For example if N is 1000, the sum of all multiples of 3 under 1000 is 3 + 6 + 9 ..... 999 => 3( 1 + 2 + 3 .... 333)
Similarly for 5, sum is 5(1 + 2 + 3 .... 200). But we have to subtract common multiples like 15, 30, 45 (multiples of 15)
And sum of first N natural numbers is N*(N+1)/2;
Putting all of this together
// Returns sum of first N natural numbers
const sumN = N => N*(N+1)/2;
// Returns number of multiples of a below N
const noOfMulitples = (N, a) => Math.floor((N-1)/a);
function sumOfMulitples(N) {
const n3 = noOfMulitples(N, 3); // Number of multiples of 3 under N
const n5 = noOfMulitples(N, 5); // Number of multiples of 5 under N
const n15 = noOfMulitples(N, 15); // Number of multiples of 3 & 5 under N
return 3*sumN(n3) + 5*sumN(n5) - 15*sumN(n15);
}
You can just run a loop from 1 to number, and use the modulo operator % to check if i divides 3 or 5:
function sumOfMultiples(number) {
var result = 0;
for (var i = 0; i < number; i++) {
if (i % 5 == 0 || i % 3 == 0) {
result += i;
}
}
return result;
}
console.log(sumOfMultiples(1000));
console.log(sumOfMultiples(100000));
console.log(sumOfMultiples(10000000));
You can do that just using a single loop.
function sumOfMultiples(number) {
let sum = 0;
for(let i = 1; i < number; i++){
if(i % 3 === 0 || i % 5 === 0){
sum += i;
}
}
return sum;
}
console.time('t');
console.log(sumOfMultiples(100000))
console.timeEnd('t')
You can do something like this
Set the difference equal to 5 - 3
Start loop with current as 0, keep looping until current is less than number,
Add 3 to current in every iteration,
Add difference to current and check if it is divisible by 5 only and less than number, than add it final result,
Add current to final result
function sumOfMultiples(number) {
let num = 0;
let difference = 5 - 3
let current = 0
while(current < number){
current += 3
let temp = current + difference
if((temp % 5 === 0) && (temp %3 !== 0) && temp < number ){
num += temp
}
difference += 2
if(current < number){
num += current
}
}
return num
}
console.log(sumOfMultiples(20))
console.log(sumOfMultiples(1000));
console.log(sumOfMultiples(100000));
console.log(sumOfMultiples(10000000));
you can do something like this
function multiplesOfFiveAndThree(){
let sum = 0;
for(let i = 1; i < 1000; i++) {
if (i % 3 === 0 || i % 5 === 0) sum += i;
}
return sum;
}
console.log(multiplesOfFiveAndThree());

A non-repeating pseudo random number generator in JavaScript

I want to generate 6-digit numeric coupon codes in JavaScript.
I'd like to use something like Preshing's algorithm.
This is what I have so far,
const p = 1000003;
function permuteQPR(x) {
const residue = x * x % p;
return (x <= p/2) ? residue : p - residue;
}
function next() {
return permuteQPR(
(permuteQPR(m_index++) + m_intermediateOffset) ^ 0x5bf03635
);
};
const seedBase = 123456;
const seedOffset = 44;
m_index = permuteQPR(permuteQPR(seedBase) + 0x682f0161);
m_intermediateOffset = permuteQPR(
permuteQPR(seedOffset) + 0x46790905
);
for (i = 0; i < 20; i++) {
document.body.innerHTML += ('000000' + next()).substr(-6) + "<br>";
}
There is also a jsfiddle.
This one works and is unique:
const p = 1000003;
const seed1 = 123456;
const seed2 = 123457;
function calculateResidue(x) {
const residue = x * x % p;
return (x <= p/2) ? residue : p - residue;
}
function valueForIndex(index) {
const first = calculateResidue((index + seed1) % p);
return result = calculateResidue((first + seed2) % p);
};
let codes = [];
for(i=0;i<1000000;i++) {
const code = valueForIndex(i);
if(codes.indexOf(code)==-1) codes.push(code);
};
document.body.innerHTML += "Unique codes: " + codes.length;

Categories

Resources