Vuelta atrás (profundidad primero estado de reposición + + ciruela pasa)

1. ¿Qué es algoritmo de retroceso

algoritmo "Backtracking", también conocido como algoritmo de "retroceso de búsqueda", que se utiliza principalmente en un gran espacio de búsqueda problemas que necesitan una solución. "Backtracking" se refiere al "estado de reposición" puede entenderse como "Volver al pasado", "sitio de recuperación", está en el proceso de codificación, una técnica utilizada con el fin de ahorrar espacio. La parte posterior es en realidad un "recorrido en profundidad" peculiar fenómeno. La razón es el "recorrido en profundidad" porque el problema que tenemos que resolver por lo general se hace en un árbol, en respuesta a esta búsqueda árbol necesidades, generalmente por medio de un recorrido en profundidad.

2. Ejemplo 1 (de nuevo + estado de reposición)

"Gama completa" es una aplicación muy clásico "retrospectiva" del algoritmo. Sabemos completa gama de N números de un total de n! Tantos.

Un array [1, 2, 3] de toda la disposición de un ejemplo.

  • En primer lugar, escribimos al principio de la matriz completa 1, que son: [1, 2, 3], [1, 3, 2];
  • En el comienzo de la gama 2, que es: [2, 1, 3], [2, 3, 1];
  • Por último, con el fin de escribir el principio de la matriz completa 3, que es: [3, 1, 2], [3, 2, 1]

Sólo tenemos que enumerar de acuerdo con el orden de todas las situaciones que pueden presentarse, hemos seleccionado los números no aparecen en las cifras que se determinarán de la siguiente. En esta estrategia seleccionada será capaz de hacer no se escapan, todo el arreglo podría haber enumerado.

Obtenidos usando el método de programación de matriz completa es programado en dicha estructura un árbol como se muestra a continuación, en particular, es a realizar un recorrido en profundidad, formado a partir de la raíz del árbol hasta el nodo de hoja de un camino es la gama completa .

A continuación explicamos cómo codificar:
(1) Además de la primera raíz del árbol y de la hoja nodos, cada nodo está realmente haciendo lo mismo, que ha sido elegido bajo la premisa de algunos de los números, necesitamos izquierda el número de aún no seleccionado en el orden de seleccionar secuencialmente un número, que es obviamente una estructura recursiva
(2) recursiva condición de terminación que el número ha sido seleccionado de suficiente, y por lo tanto necesitamos una variable recursiva para indicar la corriente a las primeras capas, nos esta variable se denomina profundidad
(3) de estos nodos representan en realidad una búsqueda (encontrar) las diferentes etapas completa gama de temas, con el fin de distinguir entre estas diferentes etapas, necesitamos algunas variables para grabar el programa, donde a paso, y aquí necesitamos dos variables:
[a] que ha sido seleccionados de entre el número de los nodos hoja cuando estos números han sido seleccionados para formar una matriz completa (ruta de acceso)
[b] una matriz booleana isused, cuando se inicializan a falso indica que estos números no ha sido seleccionado, cuando se seleccionaron un número de veces, esta será la posición correspondiente en la matriz se establece en verdadero, así que la siguiente consideración Cuando la posición, es posible O complejidad (1) hora de juzgar si ha sido seleccionado el número, se trata de un pensamiento "espacio para el tiempo"

Estas dos variables llamadas " variables de estado ", representan una etapa en la que estamos resolviendo un problema de tiempo.

(4) en un nodo no hoja, lo que resulta en diferentes ramas, la semántica de esta operación es: seleccionar un número de elemento no se ha seleccionado como la ubicación del elemento siguiente, lo que obviamente tiene que ser alcanzado por un ciclo.
(5) Desde la implementación del recorrido en profundidad, los rendimientos de más profundo a nodo de enlace superficial cuando la necesidad de hacer ** "estado de reposición", o "vuelta al pasado", "restaurar el sitio," el recién se añadió al número variable de ruta de expulsión, y la posición se establece en False array isused ** correspondiente a
un programa implementado

def permute(self, nums: List[int]) -> List[List[int]]:
        pre = []     # pre相当于上面说的path
        res = []
        isused = [False for _ in nums]
        self.digui(nums, isused, pre, res)
        return res
        
    def digui(self, nums, isused, pre, res):
        
        #判断递归结束
        if len(pre) == len(nums):
            res.append(pre.copy())   # 此处需要注意,不可使用res.append(pre), 因为后面对pre的改变此处也会随之改变,因此需要深度复制
            return
        
        for i in range(len(nums)):
            if isused[i]:
                continue
            else:
                pre.append(nums[i])
                isused[i] = True
            
            self.digui(nums, isused, pre, res)
            isused[i] = False
            pre.pop()

2.2 Análisis de Complejidad

(De vuelta en el tiempo la complejidad del algoritmo es generalmente más alta, algunos problemas son complejos análisis, yo personalmente no sienten la necesidad de dominar, y la poda cizallas así, entonces, la complejidad a caer muy bajo, y por lo tanto el análisis del peor tiempo de complejidad el significado no es muy grande, como puede ser el caso).
el tiempo de complejidad: O (NxN)!

3. Ejemplo 2 (sin dar marcha atrás estado de reposición)

Dados dos números enteros n y k, 1 ... Devuelve el número de todas las combinaciones posibles de n, k

输入: n = 4, k = 2
输出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

En este ejemplo, hay necesidad de proporcionar isuseduna matriz a la que se utiliza la grabación digital, debido a que diferentes combinaciones y permutaciones, para la combinación, el [1, 2] y [2, 1] es la misma combinación, pero para los propósitos de alineación, es diferente arreglos

programa completo

class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:

        if n == [] or k>n:
            return []
        path = []
        result = []
        start = 1
        self.digui(path, result, start, k, n)
        return result

    def digui(self, path, result, start, k, n):
        if len(path) == k:
            result.append(path[:])
            return

        for i in range(start, n+1):
            path.append(i)
            start += 1
            self.digui(path, result, start, k, n)
            path.pop()

4. Ejemplo 3 (back + + poda estado de reposición)

Dada una secuencia de números puede incluir la repetición, devolver todos arsenal completo distinto.

输入: [1,1,2]
输出:
[
  [1,1,2],
  [1,2,1],
  [2,1,1]
]

Aquí el sujeto pidió que buscara todas arsenal completo distinta, es decir, se requiere para el peso, por lo que dar marcha atrás debe ser podado para lograr un efecto de énfasis, los siguientes procedimientos:

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        res = []
        pre = []
        isused = [False]*len(nums)
        # 先进行排序
        nums.sort()
        self.digui(nums, isused, pre, res)
        return res
        
    def digui(self, nums, isused, pre, res):
        
        if len(pre) == len(nums):
            res.append(pre.copy())
            return
        
        for i in range(len(nums)):
            # 增加条件剪枝去重
            if i>0 and nums[i]==nums[i-1] and isused[i-1]==False or isused[i]:
                continue
            else:
                isused[i]=True
                pre.append(nums[i])
            
            self.digui(nums, isused, pre, res)
            isused[i] = False
            pre.pop()

La idea general es el primer elemento de la lista está ordenada, entonces el método de acuerdo con el Ejemplo 1 vuelta hacia atrás para encontrar todas las permutaciones, añadir condiciones a nums[i]==nums[i-1] and isused[i-1]==Falsellevar a cabo la poda, y por qué esta condición puede poda, árbol de búsqueda se pintó la simulación de procesos se puede encontrar

5. Resumen

En primer dibujo, el dibujo es muy importante, dibujo sólo puede ayudarnos a pensar con claridad la estructura recursiva, para saber cómo podar. En el proceso de elaboración de pensar con claridad:
(1) ¿Cómo generar sucursal;
la solución (2) Cuando el sujeto que lo necesita? En los nodos de hoja, o en los nodos que no son hojas, o desde el nodo con los nodos de la hoja de la ruta?
(3) no tienen que buscar soluciones que producirán? Por ejemplo: generar repita la razón que sea, si es poco profunda conocía esta rama no puede producir los resultados deseados, se debe podar por adelantado, lo que las condiciones se poda, cómo escribir código?

6. Referencias

leetcode solución arsenal completo a un problema

Publicado 33 artículos originales · ganado elogios 1 · vistas 2605

Supongo que te gusta

Origin blog.csdn.net/orangerfun/article/details/104281867
Recomendado
Clasificación