[Programación dinámica] LeetCode-139. Word Split-DFS, BFS, DP

139. Palabra dividida

Descripción del Título

Dada una cadena no vacía s y una lista wordDict que contiene palabras no vacías, determine si s se puede dividir por espacios en una o más palabras que aparecen en el diccionario.

Descripción:

Las palabras del diccionario se pueden reutilizar al dividir.
Puede suponer que no hay palabras repetidas en el diccionario.
Ejemplo 1:

Entrada: s = "leetcode", wordDict = ["leet", "code"]
Salida: verdadero
Explicación: Devuelve verdadero porque "leetcode" se puede dividir en "leet code".
Ejemplo 2:

Entrada: s = "applepenapple", wordDict = ["apple", "pen"]
Salida: true
Explicación: Devuelve true porque "applepenapple" se puede dividir en "apple pen apple".
Tenga en cuenta que puede reutilizar palabras en el diccionario.
Ejemplo 3:

Entrada: s = "catsandog", wordDict = ["gatos", "perro", "arena", "y", "gato"]
Salida: falso

Ideas para resolver problemas

(1) pensamiento DFS

  1. Método DFS sin búsqueda de memoria
  • Si "leetcode" puede romperse se puede dividir en:

    • Si "l" es una palabra en la lista de palabras y si las subcadenas restantes pueden romperse.
    • Si "le" es una palabra en la lista de palabras y si las subcadenas restantes pueden romperse.
    • "Lee" ... y así sucesivamente ...
  • Retrocediendo con DFS para examinar todas las posibles divisiones, el puntero escanea de izquierda a derecha:

    • Si la parte izquierda del puntero es una palabra, las subcadenas restantes se examinan de forma recursiva.
    • Si la parte izquierda del puntero no es una palabra, no la lea, vuelva atrás y examine otras ramas.

Árbol recursivo, el árbol espacial de la solución del problema

[Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo de enlace anti-sanguijuela. Se recomienda guardar la imagen y subirla directamente (img-higVA3tm-1616766905069) (D: \ Pictures \ labuladong_img \ 1-3_1.png )]

  1. Método DFS con búsqueda de memoria

    El puntero de inicio representa el estado del nodo. Como puede ver, se han realizado muchos cálculos repetidos:

    [Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo de enlace anti-sanguijuela. Se recomienda guardar la imagen y subirla directamente (img-NV5OUjSi-1616766905073) (D: \ Pictures \ labuladong_img \ 1-3_2.png )]

    Utilice una matriz para almacenar el resultado del cálculo. El índice de la matriz es la posición del puntero y el valor es el resultado del cálculo. La próxima vez que se encuentre con el mismo subproblema, devolverá directamente el valor almacenado en caché en la matriz sin ingresar recursividad repetida.

    [Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo de enlace anti-sanguijuela. Se recomienda guardar la imagen y subirla directamente (img-zSEBO6lO-1616766905075) (D: \ Pictures \ labuladong_img \ 1-3_3.png )]

Código:

// BFS
    public boolean wordBreak(String s, List<String> wordDict) {
    
    
        Queue<Integer> queue = new LinkedList<>();
        queue.add(0);

        int slength = s.length();
        boolean[] visited = new boolean[slength + 1];

        while (!queue.isEmpty()) {
    
    
            int size = queue.size();
            for (int i = 0; i < size; i++) {
    
    
                int start = queue.poll().intValue();
                for (String word : wordDict) {
    
    
                    int nextStart = start + word.length();
                    if (nextStart > slength || visited[nextStart]) {
    
    
                        continue;
                    }

                    if (s.indexOf(word, start) == start) {
    
    
                        if (nextStart == slength) {
    
    
                            return true;
                        }

                        queue.add(nextStart);
                        visited[nextStart] = true;
                    }
                }
            }
        }

        return false;
    }

(2) BFS

1. BFS con acceso a nodos duplicados

  • Hace un momento usamos DFS para recorrer el árbol espacial y, por supuesto, también se puede usar BFS.
  • Mantener una cola, seguir usando punteros para describir un nodo y seguir observando los punteros.
  • Al principio, el puntero 0 entra en la columna y luego sale de la columna. Los punteros 1, 2, 3, 4, 5, 6, 7, 8 son sus nodos secundarios y las subcadenas de prefijo se encierran con 0 respectivamente. Si no es una palabra, el puntero correspondiente No ingrese a la lista, de lo contrario ingrese a la lista, continúe investigando las subcadenas restantes a partir de ella.
  • Luego repita: el nodo (puntero) se quita de la cola, y sus nodos secundarios se inspeccionan, y los que se pueden ingresar se ponen en cola y se quitan de la cola nuevamente ...
  • Hasta que el puntero cruza el límite, no quedan subcadenas y no se pueden ingresar punteros. Si la subcadena de prefijo es una palabra, significa que la palabra se ha cortado antes y se devuelve verdadero.
  • Si todo el proceso BFS nunca devuelve verdadero, se devuelve falso.

[Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo de enlace anti-sanguijuela. Se recomienda guardar la imagen y subirla directamente (img-Y68BEiIZ-1616766905077) (D: \ Pictures \ labuladong_img \ 1-3_4.png )]

2. BFS evita visitar nodos duplicados

El DFS sin podar atravesará los nodos repetidamente, y lo mismo es cierto para el BFS. Considere el caso del tiempo de espera, cómo BFS visita repetidamente un nodo.

Solución: Utilice un arreglo visitado para registrar los nodos visitados. Cuando salga a inspeccionar un puntero, omítalo si existe en visitado, de lo contrario guárdelo en visitado.

Código:

  // BFS
    public boolean wordBreak(String s, List<String> wordDict) {
    
    
        Queue<Integer> queue = new LinkedList<>();
        queue.add(0);

        int slength = s.length();
        boolean[] visited = new boolean[slength + 1];

        while (!queue.isEmpty()) {
    
    
            int size = queue.size();
            for (int i = 0; i < size; i++) {
    
    
                int start = queue.poll().intValue();
                for (String word : wordDict) {
    
    
                    int nextStart = start + word.length();
                    if (nextStart > slength || visited[nextStart]) {
    
    
                        continue;
                    }

                    if (s.indexOf(word, start) == start) {
    
    
                        if (nextStart == slength) {
    
    
                            return true;
                        }

                        queue.add(nextStart);
                        visited[nextStart] = true;
                    }
                }
            }
        }

        return false;
    }

(3) Planificación dinámica

  • ¿Se puede descomponer la cadena s en palabras en el vocabulario, es decir, si la primera cadena de caracteres de longitud s se puede descomponer en palabras en el vocabulario?
  • El gran problema se divide en subproblemas más pequeños. La diferencia de escala es la longitud. El problema se divide en:
    • ¿Se puede descomponer la subcadena de los primeros i caracteres en palabras?
    • Si la subcadena restante es una sola palabra.
  • dp [i]: si la subcadena s [0: i-1] de longitud i se puede dividir en palabras. El título requiere que preguntemos: dp [s.length]

[Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo de enlace anti-sanguijuela. Se recomienda guardar la imagen y subirla directamente (img-88G8oIIt-1616766993347) (D: \ Pictures \ labuladong_img \ 1-3_5.png )]

Ecuación de transición de estado

  • Usamos el puntero j para dividir la subcadena de s [0: i], como se muestra en la siguiente figura:
  • Si dp [i + 1] de la subcadena de s [0: i] es verdadero (si se puede dividir en palabras) depende de dos puntos:
    • Si dp [j] de su subcadena de prefijo s [0: j-1] es verdadero.
    • Si la subcadena restante s [j: i] es una sola palabra.

[Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo de enlace anti-sanguijuela. Se recomienda guardar la imagen y subirla directamente (img-Q0JVVZ9k-1616766993348) (D: \ Pictures \ labuladong_img \ 1-3_6.png )]

caso base

  • dp [0] = verdadero. La duración de 0 s [0: -1] se puede dividir en palabras de lista de palabras.
  • Parece absurdo, pero esto es solo para hacer que las condiciones de frontera también satisfagan la ecuación de transición de estado.
  • Cuando j = 0 (la parte amarilla en la figura anterior es una cadena vacía y la cadena de prefijo dividida por j es una cadena vacía), el dp [i + 1] de la subcadena de s [0: i] depende de la valor de s [0: -1] dp [0], y si la subcadena restante s [0: i] es una sola palabra.
  • Solo si dp [0] es verdadero, dp [i + 1] solo dependerá de si s [0: i] es una sola palabra y satisface la ecuación de transición de estado.

Programación dinámica después de la optimización

  • En el proceso iterativo, si se encuentra dp [i] == true, rompa directamente
  • Si dp [j] == falso, no hay posibilidad de que dp [i] sea verdadero, continúe y examine el siguiente j

Código:

// DP
    public boolean wordBreak(String s, List<String> wordDict) {
    
    
        int maxWordLength = 0;
        Set<String> wordSet = new HashSet<>(wordDict.size());
        for (String word : wordDict) {
    
    
            wordSet.add(word);

            if (word.length() > maxWordLength) {
    
    
                maxWordLength = word.length();
            }
        }

        boolean[] dp = new boolean[s.length() + 1];
        dp[0] = true;
        for (int i = 1; i < dp.length; i++) {
    
    
            for (int j = (i - maxWordLength < 0 ? 0 : i - maxWordLength); j < i; j++) {
    
    
                if (dp[j] && wordSet.contains(s.substring(j, i))) {
    
    
                    dp[i] = true;
                    break;
                }
            }
        }
        return dp[dp.length - 1];
    }

Referencia de imagen: fuente de imágenes en el texto

Supongo que te gusta

Origin blog.csdn.net/qq_35655602/article/details/115256164
Recomendado
Clasificación