rcpl

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub ruthen71/rcpl

:heavy_check_mark: Levenshtein Distance (レーベンシュタイン距離)
(dp/levenshtein_distance.hpp)

Edit Distance (編集距離) とも呼ばれ, 1 文字の挿入, 1 文字の削除, 1 文字の置換を行うことで $s$ を $t$ に一致させるための操作回数を表す

DP のイメージは LCS と似ており, 編集前の $s$ における各文字が $t$ のどの文字と対応するかを考えながら計算を進める

LCS では dp 配列の更新が $s_i = t_j$ となるような対応付けを行うときのみ発生していたため, dp[n][j]dp[i][m] からの更新は発生しなかったが, Levenshtein Distance の場合は dp[n][j] から $s$ に 1 文字挿入を行うことで dp[n][j + 1] を更新できるため, i = nj = m からも遷移を計算する必要がある

使い方

std::string s, t;
auto d = levenshtein_distance(s, t);

参考文献

Verified with

Code

#pragma once

#include <vector>
#include <string>

template <class T>
int levenshtein_distance(std::vector<T>& a, std::vector<T>& b, const int inf = 1000000000) {
    const int n = (int)(a.size()), m = (int)(b.size());
    std::vector dp(n + 1, std::vector<int>(m + 1, inf));
    // initialize
    dp[0][0] = 0;
    // もらう DP だと dp[i][0], dp[0][j] について初期化が必要
    // for (int i = 0; i < n + 1; i++) dp[i][0] = i;
    // for (int j = 0; j < m + 1; j++) dp[0][j] = j;
    // dp
    for (int i = 0; i <= n; i++) {
        for (int j = 0; j <= m; j++) {
            // a += ?
            if (j + 1 <= m and dp[i][j + 1] > dp[i][j] + 1) {
                dp[i][j + 1] = dp[i][j] + 1;
            }
            // b += ?
            if (i + 1 <= n and dp[i + 1][j] > dp[i][j] + 1) {
                dp[i + 1][j] = dp[i][j] + 1;
            }
            // a[i] = b[i]
            if (i + 1 <= n and j + 1 <= m) {
                int cost = a[i] == b[j] ? 0 : 1;
                if (dp[i + 1][j + 1] > dp[i][j] + cost) {
                    dp[i + 1][j + 1] = dp[i][j] + cost;
                }
            }
        }
    }
    return dp[n][m];
}

int levenshtein_distance(std::string& s, std::string& t, const int inf = 1000000000) {
    const int n = (int)(s.size()), m = (int)(t.size());
    std::vector<int> a(n), b(m);
    for (int i = 0; i < n; i++) a[i] = s[i];
    for (int j = 0; j < m; j++) b[j] = t[j];
    return levenshtein_distance(a, b, inf);
}
#line 2 "dp/levenshtein_distance.hpp"

#include <vector>
#include <string>

template <class T>
int levenshtein_distance(std::vector<T>& a, std::vector<T>& b, const int inf = 1000000000) {
    const int n = (int)(a.size()), m = (int)(b.size());
    std::vector dp(n + 1, std::vector<int>(m + 1, inf));
    // initialize
    dp[0][0] = 0;
    // もらう DP だと dp[i][0], dp[0][j] について初期化が必要
    // for (int i = 0; i < n + 1; i++) dp[i][0] = i;
    // for (int j = 0; j < m + 1; j++) dp[0][j] = j;
    // dp
    for (int i = 0; i <= n; i++) {
        for (int j = 0; j <= m; j++) {
            // a += ?
            if (j + 1 <= m and dp[i][j + 1] > dp[i][j] + 1) {
                dp[i][j + 1] = dp[i][j] + 1;
            }
            // b += ?
            if (i + 1 <= n and dp[i + 1][j] > dp[i][j] + 1) {
                dp[i + 1][j] = dp[i][j] + 1;
            }
            // a[i] = b[i]
            if (i + 1 <= n and j + 1 <= m) {
                int cost = a[i] == b[j] ? 0 : 1;
                if (dp[i + 1][j + 1] > dp[i][j] + cost) {
                    dp[i + 1][j + 1] = dp[i][j] + cost;
                }
            }
        }
    }
    return dp[n][m];
}

int levenshtein_distance(std::string& s, std::string& t, const int inf = 1000000000) {
    const int n = (int)(s.size()), m = (int)(t.size());
    std::vector<int> a(n), b(m);
    for (int i = 0; i < n; i++) a[i] = s[i];
    for (int j = 0; j < m; j++) b[j] = t[j];
    return levenshtein_distance(a, b, inf);
}
Back to top page