Categorías
Algorithms

Leetcode – Salto de palabras (Java)

Dada una cadena sy un diccionario de palabras dict, determine si s se puede segmentar en una secuencia separada por espacios de una o más palabras del diccionario.

Por ejemplo, dado
s = «código de acceso»,
dict = [«leet», «code»].

Devuelve verdadero porque «leetcode» se puede segmentar como «leet code».

1. Enfoque ingenuo

Este problema puede resolverse utilizando un enfoque ingenuo, que es trivial. Sin embargo, una discusión siempre puede comenzar a partir de ahí.

public class Solution {
    public boolean wordBreak(String s, Set<String> dict) {
             return wordBreakHelper(s, dict, 0);
    }
 
    public boolean wordBreakHelper(String s, Set<String> dict, int start){
        if(start == s.length()) 
            return true;
 
        for(String a: dict){
            int len = a.length();
            int end = start+len;
 
            //end index should be <= string length
            if(end > s.length()) 
                continue;
 
            if(s.substring(start, start+len).equals(a))
                if(wordBreakHelper(s, dict, start+len))
                    return true;
        }
 
        return false;
    }
}

El tiempo es O (n ^ 2) y excede el límite de tiempo.

2. Programación dinámica

La clave para resolver este problema mediante el uso de un enfoque de programación dinámica:

  • Definir una matriz t[] tal que t[i]== true => 0- (i-1) se puede segmentar usando el diccionario
  • Estado inicial t[0] == verdadero
  LeetCode - Rangos de resumen (Java)
public class Solution {
    public boolean wordBreak(String s, Set<String> dict) {
        boolean[] t = new boolean[s.length()+1];
        t[0] = true; //set first to be true, why?
        //Because we need initial state
 
        for(int i=0; i<s.length(); i++){
            //should continue from match position
            if(!t[i]) 
                continue;
 
            for(String a: dict){
                int len = a.length();
                int end = i + len;
                if(end > s.length())
                    continue;
 
                if(t[end]) continue;
 
                if(s.substring(i, end).equals(a)){
                    t[end] = true;
                }
            }
        }
 
        return t[s.length()];
    }
}

Hora: O (longitud de la cadena * tamaño del dictado).

3. Java Solution 3: simple y eficiente

En la Solución 2, si el tamaño del diccionario es muy grande, el tiempo es malo. En cambio, podemos resolver el problema en O (n ^ 2) tiempo (n es la longitud de la cadena).

public boolean wordBreak(String s, Set<String> wordDict) {
    int[] pos = new int[s.length()+1];
 
    Arrays.fill(pos, -1);
 
    pos[0]=0;
 
    for(int i=0; i<s.length(); i++){
        if(pos[i]!=-1){
            for(int j=i+1; j<=s.length(); j++){
                String sub = s.substring(i, j);
                if(wordDict.contains(sub)){
                    pos[j]=i;
                }
            } 
        }
    }
 
    return pos[s.length()]!=-1;
}
  LeetCode - Producto máximo de longitudes de palabras (Java)

4. El problema más interesante

La solución dinámica puede decirnos si la cadena se puede dividir en palabras, pero no puede decirnos en qué palabras se divide la cadena. Entonces, ¿cómo conseguir esas palabras?

Echa un vistazo a Word Break II.

Por Programación.Click

Más de 20 años programando en diferentes lenguajes de programación. Apasionado del code clean y el terminar lo que se empieza. ¿Programamos de verdad?

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *