Enumera todas las formas en que 1, 2 y 3 pueden sumar 4, el orden es importante. Por ejemplo, [1, 1, 1, 1] es una forma. [1,1,2] es diferente de [1,2,1]
He descubierto una forma en que funciona en papel. Pero todavía no puedo escribir el código para ello. Por favor, ayuda y mira esta imagen de Mi idea para mayor claridad.
Este código que escribí falló. Pero esto es lo lejos que tengo.
function theseAddToSum(steps = [], sum) { let results = []; if (steps.length < 1) return 'error' for (let i = 0; i < steps.length; i++) { let cur = steps[i]; let remaining = sum - cur; if (remaining >= 0) { console.log('sum', sum, 'step', cur) let c = theseAddToSum(steps, remaining) } } return results } console.log(theseAddToSum([1, 2, 3], 4)) Como console.log('sum', sum, 'step', cur) , obtengo los resultados deseados:
sum 4 step 1 sum 3 step 1 sum 2 step 1 sum 1 step 1 sum 2 step 2 sum 3 step 2 sum 1 step 1 sum 3 step 3 sum 4 step 2 sum 2 step 1 sum 1 step 1 sum 2 step 2 sum 4 step 3 sum 1 step 1 Mi problema es que no sé cómo enviar el resultado a la matriz de results . Debería verse como [[1,1,1,1], [1,1,2], [1,2,1], [1,3], [2,1,1], and on]
Algunos asuntos:
Aunque el array devuelto por la llamada recursiva está capturado en la variable c , esa variable no se usa más adelante, por lo que ha sido inútil.
results se inicializa como [] , pero luego nunca se modifica/extiende, por lo que se garantiza que el return result final devuelto devolverá esa lista vacía.
Los dos problemas anteriores deben resolverse iterando las soluciones presentes en c : agregue el valor actual a esas soluciones (ya que restamos ese valor para obtener esas soluciones) y agregue esas soluciones extendidas a la matriz de results actual.
Cuando remaining es igual a 0, no tiene sentido hacer más llamadas recursivas. Este es en realidad un caso base de la recursividad. (Prefiero hacer esta verificación un nivel más profundo en la recursividad, al comienzo de la función: si la suma es 0, deberíamos devolver una solución vacía que luego puede extenderse por los valores seleccionados a medida que salimos de la recursividad) .
Sin relación, pero es una mejor práctica separar sus declaraciones con punto y coma. No sería el primero en caer en una de las trampas de la inserción automática de punto y coma . Mejor toma el control.
Aquí hay una versión corregida:
function theseAddToSum(steps = [], sum) { // Base cases: if (sum < 0) return []; // No solutions if (sum == 0) return [[]]; // A solution let results = []; if (steps.length < 1) return 'error'; for (let i = 0; i < steps.length; i++) { let cur = steps[i]; let remaining = sum - cur; let c = theseAddToSum(steps, remaining) // Use the solutions we got back from recursion for (let solution of c) { solution.push(cur); // ... then extend them results.push(solution); // ... and collect them } } return results; } console.log(theseAddToSum([1, 2, 3], 4));Esta es una oportunidad perfecta para usar backtracking . La idea de retroceder es que nos propusimos probar todas las combinaciones posibles, pero cuando nuestra combinación actual falla y no podemos continuar construyendo sobre ella, entonces regresamos e intentamos otra cosa.
La forma en que abordamos un problema de retroceso es la siguiente:
[1,2,3]solutionSon muchas palabras, resolvamos la pregunta:
const getSum = (arr) => arr.reduce((acc, num) => num + acc, 0); function theseAddToSum(steps, sum) { const solutions = []; function recurse(steps, sum, currentSol) { if (getSum(currentSol) === sum) { solutions.push([...currentSol]); return } for (let i = 0; i < steps.length; i++) { currentSol.push(steps[i]); if (getSum(currentSol) <= sum) { recurse(steps, sum, currentSol); } currentSol.pop(); } } recurse(steps, sum, []) return solutions; } console.log(theseAddToSum([1, 2, 3], 4));