39 Suma combinada (dfs)

1. Descripción del problema:

Dada una variedad de candidatos sin elementos repetitivos y un objetivo de número objetivo, encuentre todas las combinaciones de candidatos que puedan hacer que el objetivo sea la suma de números.

Los números en los candidatos se pueden seleccionar repetidamente sin restricción.

Descripción:

Todos los números (incluido el objetivo) son enteros positivos.
El conjunto de soluciones no puede contener combinaciones duplicadas. 
Ejemplo 1:

Entrada: candidatos = [2,3,6,7], objetivo = 7,
el conjunto resuelto es:
[
  [7],
  [2,2,3]
]
Ejemplo 2:

Entrada: candidatos = [2,3,5], objetivo = 8,
el conjunto resuelto es:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]

Fuente:
enlace de LeetCode : https://leetcode-cn.com/problems/combination-sum

2. Análisis de pensamiento:

① Se puede ver en el título que hay una característica obvia. En el proceso de componer el número objetivo, en realidad está tratando de continuar las posibles soluciones. Por ejemplo, en el primer caso de prueba, el número objetivo es 7; 3 Pero realmente no podemos estimar cuántos 2s y 3s usar o estimar que es difícil usar métodos convencionales para resolver, y dfs puede resolver este problema, porque dfs es el más adecuado para este tipo de problema. En estas circunstancias, intente una por una posibles soluciones hasta que se alcance el número objetivo o se ejecuten todos los métodos recursivos, por lo que es muy apropiado usar dfs para resolver

② Para que dfs lo resuelva, primero podemos dibujar una imagen y describir el proceso de recursión. Esto es similar al recorrido recursivo de un árbol binario. La siguiente es una imagen dibujada usando Word (muy áspero y simple, y algunos restantes no están dibujados) , El propósito de dibujar un árbol recursivo es comprender mejor todo el proceso y puede determinar claramente el valor de algunos parámetros en el método recursivo. Este problema se debe a que los requisitos no pueden repetirse, por lo que si hacemos recursivos en el bucle, necesitamos buclear variables Comience desde la posición actual en lugar de comenzar desde cero, porque solo puedo agregar el número de mi posición y el número después de mi posición para que el resultado obtenido no se repita. Si comienza desde cero, los resultados a menudo se repiten Entonces, al pasar la posición recursiva, debe pasar la posición actual en el pasado. Esto se puede combinar con el árbol recursivo para comprender un poco mejor

③ Debido a que la recursión consume mucho tiempo, debe podarse por adelantado. Podemos ordenar la matriz al principio, de modo que la recursividad en el bucle pueda juzgarse por adelantado, por ejemplo, cuando se descubre que se agrega la posición actual Después de que el valor es demasiado grande, se puede romper, porque el número detrás es mayor

④ Puede usar la pila o la cola de doble extremo para almacenar el proceso intermedio. Si usa la pila para almacenar, puede agregar los elementos de la pila a la ArrayList. No use la Lista para almacenar el proceso intermedio, porque cuando la Lista agrega elementos Si hay una modificación posterior, los elementos en la Lista también cambiarán. Si necesita usar la Lista, debe atravesar la Lista en la salida recursiva y usar otra Lista para agregar estos elementos. En general, es mejor usar la pila o la cola doble para procesar El proceso de obtener el número objetivo en el medio

3. El código es el siguiente:

import java.util.*;
public class Solution {
    List<List<Integer>> res = new ArrayList<>();
    int len = 0;
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        /*先要对数组进行排序可以减少时间复杂度*/
        Arrays.sort(candidates);
        len = candidates.length;
        recursion(candidates, target, 0, 0, new Stack());
        return res;
    }

    /*第三个参数是之前各个元素的累加和, 第四个参数表示的是当前递归的位置*/
    private void recursion(int[] candidates, int target, int cur, int pos, Stack stack) {
        if (cur == target) {
            res.add(new ArrayList<>(stack));
            return;
        }
        for (int i = pos; i < len; ++i){
            /*剪枝, 当前元素都大于了target肯定之后的元素更是加起来大于了target这个剪枝对于提升效率是很有帮助的*/
            if (cur + candidates[i] > target) break;
            stack.add(candidates[i]);
            recursion(candidates, target, cur + candidates[i], i, stack);
            /*回溯*/
            stack.pop();
        }
    }
}

 

569 artículos originales publicados · Me gusta 153 · Visitas 590,000+

Supongo que te gusta

Origin blog.csdn.net/qq_39445165/article/details/105396709
Recomendado
Clasificación