使用Go语言计算字符串编辑距离的代码实现

 更新时间:2025年07月29日 08:30:26   作者:程序员爱钓鱼  
在自然语言处理、拼写纠错、模糊搜索等场景中,我们经常需要衡量两个字符串之间的相似度,编辑距离(Edit Distance)  就是一个经典的衡量方式,它描述了将一个字符串转换为另一个字符串所需的最少操作次数,本文给大家介绍了如何使用Go语言计算字符串编辑距离

一、问题定义:什么是编辑距离?

编辑距离,也称为 Levenshtein Distance,指的是将字符串 A 转换成字符串 B 所需的最少操作次数。操作允许:

  • • 插入一个字符(Insert)
  • • 删除一个字符(Delete)
  • • 替换一个字符(Replace)

示例:

A = "kitten"
B = "sitting"

编辑距离 = 3
解释:
kitten → sitten(k → s) → sittin(e → i)→ sitting(插入 g)

二、应用场景

编辑距离广泛应用于:

  • • 搜索引擎模糊匹配(例如:“gooogle” 应该匹配 “google”)
  • • 拼写检查和自动纠正
  • • 语音识别、OCR纠错
  • • DNA序列比对

三、解决思路:动态规划(DP)

1. 状态定义

设 dp[i][j] 表示将字符串 A 的前 i 个字符转换成字符串 B 的前 j 个字符所需的最小操作数。

2. 状态转移方程

我们可以从三个方向转移过来:

  • 插入:dp[i][j-1] + 1(B 多了个字符)
  • 删除:dp[i-1][j] + 1(A 多了个字符)
  • 替换或匹配:dp[i-1][j-1] + cost
    • 如果 A[i-1] == B[j-1]cost = 0
    • 否则 cost = 1

最终状态转移为:

dp[i][j] = min(
    dp[i-1][j] + 1,          // 删除
    dp[i][j-1] + 1,          // 插入
    dp[i-1][j-1] + cost      // 替换/匹配
)

3. 初始化

  • dp[0][j] = j:将空串变成 B 前 j 个字符需要插入 j 次;
  • dp[i][0] = i:将 A 前 i 个字符变成空串需要删除 i 次。

四、Go语言实现

动态规划二维实现:

package main

import (
    "fmt"
    "math"
)

func MinDistance(a, b string) int {
    m, n := len(a), len(b)
    dp := make([][]int, m+1)

    // 初始化二维数组
    for i := range dp {
        dp[i] = make([]int, n+1)
    }

    // 初始化第一列和第一行
    for i := 0; i <= m; i++ {
        dp[i][0] = i
    }
    for j := 0; j <= n; j++ {
        dp[0][j] = j
    }

    // 状态转移
    for i := 1; i <= m; i++ {
        for j := 1; j <= n; j++ {
            cost := 0
            if a[i-1] != b[j-1] {
                cost = 1
            }
            dp[i][j] = min(
                dp[i-1][j]+1,   // 删除
                dp[i][j-1]+1,   // 插入
                dp[i-1][j-1]+cost, // 替换/匹配
            )
        }
    }

    return dp[m][n]
}

func min(a, b, c int) int {
    return int(math.Min(float64(a), math.Min(float64(b), float64(c))))
}

func main() {
    a := "kitten"
    b := "sitting"
    fmt.Printf("编辑距离 between '%s' and '%s' is: %d\n", a, b, MinDistance(a, b))
}

五、运行示例

输入:
a = "kitten"
b = "sitting"

输出:
编辑距离 between 'kitten' and 'sitting' is: 3

六、时间与空间复杂度分析

  • 时间复杂度:O(m * n)
    因为我们遍历了大小为 m x n 的二维数组;
  • 空间复杂度:O(m * n)
    用于存储状态的二维数组。

七、空间优化版本(滚动数组)

可以优化为一维数组来降低空间:

func MinDistanceOptimized(a, b string) int {
    m, n := len(a), len(b)
    prev := make([]int, n+1)
    curr := make([]int, n+1)

    // 初始化第一行
    for j := 0; j <= n; j++ {
        prev[j] = j
    }

    for i := 1; i <= m; i++ {
        curr[0] = i
        for j := 1; j <= n; j++ {
            cost := 0
            if a[i-1] != b[j-1] {
                cost = 1
            }
            curr[j] = min(
                curr[j-1]+1,      // 插入
                prev[j]+1,        // 删除
                prev[j-1]+cost,   // 替换
            )
        }
        prev, curr = curr, prev
    }

    return prev[n]
}

八、拓展:支持更多操作的变种编辑距离

  • Damerau-Levenshtein 距离:除了插入、删除、替换,还支持交换相邻字符
  • 带权重的编辑距离:不同操作赋予不同代价;
  • 相似度计算:将编辑距离转为百分比相似度,比如:
similarity := 1 - float64(distance) / float64(max(len(a), len(b)))

九、实战应用场景举例

场景作用描述
搜索引擎用户输入有误时自动推荐相似关键词
拼写检查IDE、文本编辑器纠正英文单词
语音/图像识别后处理自动修正识别错误的单词序列
文件比对工具如 Git diff、文本比较器
生物信息学DNA/RNA 序列比对、蛋白质比对

十、总结

点位内容
算法思想动态规划
实现结构dp[i][j] 表示 A 的前 i 个字符转换为 B 的前 j 个字符的最小编辑距离
时间复杂度O(m * n)
空间优化支持优化为滚动数组,空间降为 O(n)
实战价值应用场景极广,从 NLP 到搜索再到生物信息学

以上就是使用Go语言计算字符串编辑距离的代码实现的详细内容,更多关于Go计算字符串编辑距离的资料请关注脚本之家其它相关文章!

相关文章

  • golang判断结构体为空的问题

    golang判断结构体为空的问题

    这篇文章主要介绍了golang判断结构体为空的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • Go关键字defer的使用和底层实现

    Go关键字defer的使用和底层实现

    defer是Go语言的关键字,一般用于资源的释放和异常的捕捉,defer语句后将其后面跟随的语句进行延迟处理,就是说在函数执行完毕后再执行调用,也就是return的ret指令之前,本文给大家介绍了Go关键字defer的使用和底层实现,需要的朋友可以参考下
    2023-11-11
  • 浅谈一下前端http与https有什么区别

    浅谈一下前端http与https有什么区别

    这篇文章主要介绍了浅谈一下前端http与https有什么区别,现今大部分的网站都已经使用了 https 协议,那么https对比http协议有哪些不同呢,需要的朋友可以参考下
    2023-04-04
  • Golang中数据结构Queue的实现方法详解

    Golang中数据结构Queue的实现方法详解

    这篇文章主要给大家介绍了关于Golang中数据结构Queue的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2017-09-09
  • Go语言中进行API限流的实战详解

    Go语言中进行API限流的实战详解

    API 限流是控制和管理应用程序访问量的重要手段,旨在防止恶意滥用、保护后端服务的稳定性和可用性,下面我们就来看看如何在Go语言中具体实现吧
    2025-01-01
  • Go Excelize API源码阅读SetSheetViewOptions示例解析

    Go Excelize API源码阅读SetSheetViewOptions示例解析

    这篇文章主要为大家介绍了Go-Excelize API源码阅读SetSheetViewOptions示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • 如何利用golang运用mysql数据库

    如何利用golang运用mysql数据库

    这篇文章主要介绍了如何利用golang运用mysql数据库,文章对依赖包、db对象注入ApiRouter等内容,需要的小伙伴可以参考一下
    2022-03-03
  • go语言开发中如何优雅得关闭协程方法

    go语言开发中如何优雅得关闭协程方法

    这篇文章主要为大家介绍了go语言开发中如何优雅得关闭协程方法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • Go 编程复杂数据类型 Map

    Go 编程复杂数据类型 Map

    这篇文章主要介绍了Go编程复杂数据类型Map,Go中的Map是一组无需的K-V类型的数据,与Python中的字典Dict和Java中的HashMap结构类似。未被初始化的Map为nil
    2022-08-08
  • Go 1.21新增的slices包中切片函数用法详解

    Go 1.21新增的slices包中切片函数用法详解

    Go 1.21新增的 slices 包提供了很多和切片相关的函数,可以用于任何类型的切片,本文通过代码示例为大家介绍了部分切片函数的具体用法,感兴趣的小伙伴可以了解一下
    2023-08-08

最新评论