Editar distancia (algoritmo de distancia de Levenshtein)

1233356-5aac7b8bda66ee24.png

La distancia de edición se refiere al número mínimo de operandos requeridos para convertir la cadena de caracteres A en la cadena de caracteres B mediante la manipulación de caracteres. Aquí solo se definen tres tipos de operaciones de edición de un solo carácter:

  • Insertar (inserción)
  • Eliminar
  • Sustitución

Por ejemplo, las dos palabras "gatito" y "sentado" que deben convertirse de "gatito" a "sentado" son:

1.kitten → sitten (substitution of "s" for "k")
2.sitten → sittin (substitution of "i" for "e")
3.sittin → sitting (insertion of "g" at the end)

Por lo tanto, la distancia de edición entre las dos palabras "gatito" y "sentado" es 3.

En general, cuanto menor es la distancia de edición de las dos cadenas, más similares son. Si las dos cadenas son iguales, su distancia de edición (por conveniencia, la "distancia" que aparece más adelante en este artículo, si no hay una explicación especial, el valor predeterminado es "distancia de edición") es 0 (no se requiere ninguna operación).

No es difícil analizar que la distancia de edición de las dos cadenas no debe exceder su longitud máxima (primero puede modificar cada carácter de la cadena corta al carácter en la posición correspondiente de la cadena larga, y luego insertar los caracteres restantes en la cadena larga).

Definición formal

1233356-3ee70deec06cfa27.png
1233356-66692149faf92252.png

Descripción del problema

Dadas dos cadenas de caracteres A y B, descubra cuántas operaciones de caracteres, al menos, la cadena de caracteres A va a convertirse en la cadena de caracteres B.

Resolución de problemas

  1. Cuando la longitud de una de las cadenas es 0, la distancia de edición es la longitud de la otra cadena (podemos entender que la cadena de caracteres con una longitud de 0 siempre se inserta en otra cadena)

  2. Cuando las cadenas no son iguales, siempre comenzamos desde el principio de la cadena.

    Entonces A [0] = B [0]; Entonces, la distancia de edición sigue siendo 0 en este momento, podemos eliminar directamente el primer carácter de la cadena. Debido a que la distancia de edición entre A y B debe ser igual a A [ 1] .. A [A.length-1], B [1] .. B [B.length-1] edite la distancia de ambos.

    Si A [0]! = B [0], entonces tenemos que considerar mucho en este momento, ¿A [0] será igual a B [1], así que simplemente agregue un carácter. B [0] No será igual a A [1], o A [1] y B [1] no serán iguales.

    Si miramos hacia adelante desde atrás, ij representa la longitud de a, b, dejamos que el método para encontrar la distancia de edición sea f

    Cuando a [i] = a [j], f (i, j) = f (i-1, j-1);

    a [i]! = A [j], f (i, j) = f (i-1, j-1) + 1; o f (i, j-1) +1 o f (i-1, j) + 1;

    Entonces la ecuación de transferencia dinámica en este momento es

   f(i,j) = max(i,j)  if i与j其中一个为0<br>
   f(i,j) = f(i-1,j-1) if a[i]=a[j]
   f(i,j) = min (f(i-1,j-1) + 1,
                f(i, j-1) + 1,
                f(i-1, j) + 1);

Este es un problema de programación dinámica. Usando fórmulas podemos escribir rápidamente métodos recursivos

public static int getEditDistanceByRecursion(String a, String b, int aIndex, int bIntex) {
    if (Math.min(aIndex, bIntex) == 0) {
        return Math.max(aIndex, bIntex);
    }
    if (a.charAt(aIndex) == b.charAt(bIntex)) {
        return getEditDistanceByRecursion(a, b, aIndex - 1, bIntex - 1);
    }

    return Math.min(getEditDistanceByRecursion(a, b, aIndex - 1, bIntex - 1) + 1,
            Math.min(getEditDistanceByRecursion(a, b, aIndex, bIntex - 1) + 1,
                    getEditDistanceByRecursion(a, b, aIndex - 1, bIntex) + 1));
}

Pero la mayor desventaja de la recursividad es el cálculo repetido. El mismo resultado se calcula varias veces. Necesitamos una tabla para almacenar los resultados de los cálculos repetidos.

El código es el siguiente

public static int getEditDistance(String origin, String target) {

    if (TextUtils.isEmpty(origin) && TextUtils.isEmpty(target)) {
        return 0;
    }

    if (TextUtils.isEmpty(origin)) {
        return target.length();
    }

    if (TextUtils.isEmpty(target)) {
        return origin.length();
    }

    int[][] dp = new int[origin.length() + 1][target.length() + 1];

    for (int i = 0; i <= origin.length(); i++) {
        dp[i][0] = i;
    }

    for (int j = 0; j <= target.length(); j++) {
        dp[0][j] = j;
    }

    for (int i = 1; i <= origin.length(); i++) {
        for (int j = 1; j <= target.length(); j++) {
            if (origin.charAt(i - 1) == target.charAt(j - 1)) {
                dp[i][j] = dp[i - 1][j - 1];
            } else {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            }

            dp[i][j] = Math.min(dp[i][j], Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1));
        }
    }
    return dp[origin.length()][target.length()];
}

Si necesitamos conocer la familiaridad de dos cadenas, es:

public static float getSimilarity(String origin, String target) {

    if (TextUtils.isEmpty(origin) || TextUtils.isEmpty(target)) {
        return 0f;
    }

    return 1.0f - getEditDistance(origin, target) / (float) Math.max(origin.length(), target.length());
}

La
distancia de edición de la aplicación y el pensamiento es un algoritmo básico de PNL para medir la similitud del texto. Se puede usar como una de las características importantes de las tareas similares de texto. Se puede aplicar a muchos aspectos, como la corrección ortográfica, la verificación de duplicación de papel y el análisis de secuencias de genes. Sin embargo, sus deficiencias también son obvias: el algoritmo calcula en función de la estructura del texto en sí y no hay forma de obtener información a nivel semántico.

Como la matriz necesita ser utilizada, la complejidad del espacio es O (MN). Esto puede lograr un buen rendimiento cuando ambas cadenas son relativamente cortas. Sin embargo, si la cadena es relativamente larga, necesita mucho espacio para almacenar la matriz. Por ejemplo: si ambas cadenas tienen 20000 caracteres, el tamaño de la matriz LD es: 20000 * 20000 * 2 = 800000000 Byte = 800MB.

Referencias

[1] https://blog.csdn.net/ghsau/article/details/78903076
[2] https://en.wikipedia.org/wiki/Levenshtein_distance
[3] https://www.dreamxu.com/books /dsa/dp/edit-distance.html
[4] https://www.jianshu.com/p/a96095aa92bc
[5] https://www.jianshu.com/p/a617d20162cf


Comunidad de desarrolladores de Kotlin

1233356-4cc10b922a41aa80

La cuenta pública de la primera comunidad de desarrolladores de Kotlin en China, que comparte e intercambia principalmente temas relacionados, como el lenguaje de programación Kotlin, Spring Boot, Android, React.js / Node.js, programación funcional e ideas de programación.

Cuanto más ruidoso es el mundo, más pensamiento pacífico se necesita.

1665 artículos originales publicados · 1067 elogiados · 750,000 vistas

Supongo que te gusta

Origin blog.csdn.net/universsky2015/article/details/105265892
Recomendado
Clasificación