With given array on unique numbers which are always greater than 0 I need to find all possible unique combinations of those numbers that are equal to a certain number when summed.
For example, getNumberComponents([7, 4, 3, 2, 5, 6, 8, 1], 8)
should return
[ [ 7, 1 ], [ 4, 3, 1 ], [ 3, 5 ], [ 2, 5, 1 ], [ 2, 6 ], [ 8 ] ]
because sum of all numbers in every subarray equals 8
.
My solution:
function getNumberComponents(numArray, number) {
const arrayLength = numArray.length;
const allVariants = [];
function findComponents(currentIndex = 0, currentVariant = []) {
while (currentIndex < arrayLength) {
const currentElement = numArray[currentIndex];
const currentSum = currentVariant.reduce((acc, cur) => acc + cur, 0);
const sumWithCurrent = currentSum + currentElement;
if (sumWithCurrent === number) {
allVariants.push([...currentVariant, currentElement]);
}
currentIndex++;
if (sumWithCurrent < number) {
findComponents(currentIndex, [...currentVariant, currentElement]);
}
}
}
findComponents();
return allVariants;
}
But I wonder if it's possible to use tail recursion for that? I have no idea how to turn my solution into tail recursion.
To make this tail recursive, you could:
Keep track of all indices that were selected to arrive at the current sum. That way you can easily replace a selected index with the successor index.
In each execution of the function get the "next" combination of indices. This could be done as follows:
Instead of accumulating a sum, you could also decrease the number
that you pass to recursion -- saving one variable.
Make the function return the array with all variants, so there is no need for an inner function, nor any action that follows the function call.
Here is an impementation:
function getNumberComponents(numArray, number, selectedIndices=[], allVariants=[]) { let i = selectedIndices.at(-1)??-1; if (number < 0) { // Sum is too large. There's no use to adding more i = numArray.length; // Force the while-condition to be true } else if (number == 0) { // Bingo allVariants.push(selectedIndices.map(idx => numArray[idx])); } while (++i >= numArray.length) { // No more successor index available if (selectedIndices.length == 0) return allVariants; // All done i = selectedIndices.pop(); // Undo a previous selection number += numArray[i]; // Remove from sum } selectedIndices.push(i); // Select index and recur: return getNumberComponents(numArray, number - numArray[i], selectedIndices, allVariants); } console.log(getNumberComponents([7, 4, 3, 2, 5, 6, 8, 1], 8));
Here is my version of your function, but using tail recursion. This is still a complex subject for me, check if there are no mistakes
function getNumberComponents(numArray, number, currentIndex = 0, currentVariant = [], allVariants = new Set()) { if (currentIndex >= numArray.length) { const currentSum = currentVariant.reduce((acc, cur) => acc + cur, 0); if (currentSum === number) { allVariants.add(currentVariant); } return Array.from(allVariants); } const currentElement = numArray[currentIndex]; const currentSum = currentVariant.reduce((acc, cur) => acc + cur, 0); const sumWithCurrent = currentSum + currentElement; if (sumWithCurrent <= number) { allVariants = new Set([...allVariants, ...getNumberComponents(numArray, number, currentIndex + 1, [...currentVariant, currentElement], allVariants), ...getNumberComponents(numArray, number, currentIndex + 1, currentVariant, new Set())]); } else { allVariants = new Set([...allVariants, ...getNumberComponents(numArray, number, currentIndex + 1, currentVariant, new Set())]); } return Array.from(allVariants); } console.log(getNumberComponents([7, 4, 3, 2, 5, 6, 8, 1], 8));
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.