Damerau-Levenshtein算法实现中的错误及更正

news2024/10/9 12:08:02

在实现 Damerau-Levenshtein 算法 时,常见的错误包括边界条件处理不当、转置操作的遗漏或误用、矩阵初始化错误等。Damerau-Levenshtein 算法是 Levenshtein 编辑距离的扩展,它不仅允许插入、删除和替换,还允许 相邻字符的转置。该算法计算两个字符串之间的编辑距离,考虑到这四种操作的最小代价。

以下是一个典型的 Damerau-Levenshtein 算法的 Python 实现,以及可能出现的错误和更正方法。

在这里插入图片描述

问题背景:

  1. 一个Python用户在Stack Overflow上发帖抱怨他实现的Damerau-Levenshtein 算法的 Cython版本速度很快,但结果不正确。
  2. 他在debug过程中发现问题似乎出在算法中用于记录编辑距离的行其中一行被错误地填满了1,而参考方法中,这一行中的值是正确的。
  3. 此外,他还遇到了另一个问题:用 malloc 分配空间给三个数组 twoago、oneago 和 thisrow 后,在循环中对它们进行轮换时,free( twoago ) 等操作会出现 double free 或内存损坏的错误。

解决方案:

  1. 对于第一个问题,问题出在循环中对数组 thisrow 的更新方式。在原始代码中,thisrow 的每一行都是通过取前一行的数据然后加1来初始化的。这种初始化方式导致 thisrow 中的所有行都包含相同的数据,因此算法无法正确计算编辑距离。
  2. 正确的初始化方式应该是只初始化 thisrow 的最后一列,其他列的值则通过计算获得。
  3. 对于第二个问题,之所以会出现 double free 或内存损坏的错误,是因为在循环中对数组的轮换方式有问题。原始代码中,twoago、oneago 和 thisrow 三个数组通过以下方式进行轮换:
twoago, oneago = oneago, thisrow
  1. 这会导致在释放数组时出现问题,因为数组实际上指向同一个内存区域,释放两次就会导致 double free 错误。
  2. 正确的轮换方式应该是:
twoago, oneago, thisrow = oneago, thisrow, twoago

代码示例:

以下是更正后的 Cython 代码:

cdef unsigned int _minimum_of_two_uints( unsigned int a, unsigned int b ):
  if a < b: return a
  return b

#-----------------------------------------------------------------------------------------------------------
cdef unsigned int _minimum_of_three_uints( unsigned int a, unsigned int b, unsigned int c ):
  if a < b:
    if c < a:
      return c
    return a
  if c < b:
    return c
  return b

#-----------------------------------------------------------------------------------------------------------
cdef inline int _warp( unsigned int limit, int value ):
  return value if value >= 0 else limit + value

############################################################################################################
# ARRAYS THAT SAY SIZE ;-)
#-----------------------------------------------------------------------------------------------------------
cdef class Array_of_unsigned_int:
  cdef unsigned int *data
  cdef unsigned int length

  #---------------------------------------------------------------------------------------------------------
  def __cinit__( self, unsigned int length, fill_value = None ):
    self.length = length
    self.data   = <unsigned int *>malloc( length * sizeof( unsigned int ) )  ###OBS### must check malloc doesn't return NULL pointer
    if fill_value is not None:
      self.fill( fill_value )

  #---------------------------------------------------------------------------------------------------------
  cdef fill( self, unsigned int value ):
    cdef unsigned int idx
    cdef unsigned int *d    = self.data
    for idx from 0 <= idx < self.length:
      d[ idx ] = value

  #---------------------------------------------------------------------------------------------------------
  cdef resize( self, unsigned int length ):
    self.data   = <unsigned int *>realloc( self.data, length * sizeof( unsigned int ) )  ###OBS### must check realloc doesn't return NULL pointer
    self.length = length

  #---------------------------------------------------------------------------------------------------------
  def free( self ):
    """Always remember the milk: Free up memory."""
    free( self.data )  ###OBS### should free memory here

  #---------------------------------------------------------------------------------------------------------
  def as_list( self ):
    """Return the array as a Python list."""
    R                       = []
    cdef unsigned int idx
    cdef unsigned int *d    = self.data
    for idx from 0 <= idx < self.length:
      R.append( d[ idx ] )
    return R


############################################################################################################
# CONVERTING UNICODE TO CHARACTER IDs (CIDs)
#---------------------------------------------------------------------------------------------------------
cdef unsigned int _UMX_surrogate_lower_bound    = 0x10000
cdef unsigned int _UMX_surrogate_upper_bound    = 0x10ffff
cdef unsigned int _UMX_surrogate_hi_lower_bound = 0xd800
cdef unsigned int _UMX_surrogate_hi_upper_bound = 0xdbff
cdef unsigned int _UMX_surrogate_lo_lower_bound = 0xdc00
cdef unsigned int _UMX_surrogate_lo_upper_bound = 0xdfff
cdef unsigned int _UMX_surrogate_foobar_factor  = 0x400

#---------------------------------------------------------------------------------------------------------
cdef Array_of_unsigned_int _cids_from_text( text ):
  """Givn a ``text`` either as a Unicode string or as a ``bytes`` or ``bytearray``, return an instance of
  ``Array_of_unsigned_int`` that enumerates either the Unicode codepoints of each character or the value of
  each byte. Surrogate pairs will be condensed into single values, so on narrow Python builds the length of
  the array returned may be less than ``len( text )``."""
  #.........................................................................................................
  # Make sure ``text`` is either a Unicode string (``str``) or a ``bytes``-like thing:
  is_bytes = isinstance( text, ( bytes, bytearray, ) )
  assert is_bytes or isinstance( text, str ), '#121'
  #.........................................................................................................
  # Whether it is a ``str`` or a ``bytes``, we know the result can only have at most as many elements as
  # there are characters in ``text``, so we can already reserve that much space (in the case of a Unicode
  # text, there may be fewer CIDs if there happen to be surrogate characters):
  cdef unsigned int           length  = <unsigned int>len( text )
  cdef Array_of_unsigned_int  R       = Array_of_unsigned_int( length )
  #.........................................................................................................
  # If ``text`` is empty, we can return an empty array right away:
  if length == 0: return R
  #.........................................................................................................
  # Otherwise, prepare to copy data:
  cdef unsigned int idx               = 0
  #.........................................................................................................
  # If ``text`` is a ``bytes``-like thing, use simplified processing; we just have to copy over all byte
  # values and are done:
  if is_bytes:
    for idx from 0 <= idx < length:
      R.data[ idx ] = <unsigned int>text[ idx ]
    return R
  #.........................................................................................................
  cdef unsigned int cid               = 0
  cdef bool         is_surrogate      = False
  cdef unsigned int hi                = 0
  cdef unsigned int lo                = 0
  cdef unsigned int chr_count         = 0
  #.........................................................................................................
  # Iterate over all indexes in text:
  for idx from 0 <= idx < length:
    #.......................................................................................................
    # If we met with a surrogate CID in the last cycle, then that was a high surrogate CID, and the
    # corresponding low CID is on the current position. Having both, we can compute the intended CID
    # and reset the flag:
    if is_surrogate:
      lo = <unsigned int>ord( text[ idx ] )
      # IIRC, this formula was documented in Unicode 3:
      cid = ( ( hi - _UMX_surrogate_hi_lower_bound ) * _UMX_surrogate_foobar_factor
            + ( lo - _UMX_surrogate_lo_lower_bound ) + _UMX_surrogate_lower_bound )
      is_surrogate = False
    #.......................................................................................................
    else:
      # Otherwise, we retrieve the CID from the current position:
      cid = <unsigned int>ord( text[ idx ] )
      #.....................................................................................................
      if _UMX_surrogate_hi_lower_bound <= cid <= _UMX_surrogate_hi_upper_bound:
        # If this CID is a high surrogate CID, set ``hi`` to this value and set a flag so we'll come back
        # in the next cycle:
        hi                = cid
        is_surrogate      = True
        continue
    #.......................................................................................................
    R.data[ chr_count ] = cid
    chr_count     += 1
  #................................................................................................

总结

  • 常见错误:主要涉及矩阵初始化、转置条件的边界检查以及转置操作的实现错误。
  • 更正:通过检查边界条件、确保字符的相邻性和正确处理转置,算法能够准确计算 Damerau-Levenshtein 编辑距离。

通过这种方式,算法不仅处理标准的编辑操作,还能优雅地处理相邻字符的转置操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2198986.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

明达IO:赋能工业机器人新未来

摘要&#xff1a; 明达技术以其卓越的分布式IO&#xff08;MR30&#xff09;与一体式IO&#xff08;MR20&#xff09;产品&#xff0c;为工业机器人行业提供了完美的信号交互解决方案。在集群式机器人应用场景中&#xff0c;MR30分布式IO以其稳定性能和自由热插拔功能&#xf…

FPGA学习(4)-时序逻辑电路实现D触发器与计数器,LED灯闪烁

1.实现原理 开发板的频率为50MHz&#xff0c;即一个周期为20ns&#xff0c;实现500ms一次翻转&#xff0c;即计数25_000_000次。每次时钟沿来一次&#xff0c;就计一次。 2. 新建工程 2.1源文件代码 在下面左边的变量值要变的&#xff0c;就用reg。不涉及的缺省&#xff1b;…

自动气象观测系统的工作原理

TH-QC8自动气象观测系统是一种能够自动采集、存储、处理和传输气象数据的系统&#xff0c;它广泛应用于气象监测、农业生产、航空安全、交通运输以及科学研究等领域。以下是对自动气象观测系统的详细介绍&#xff1a; 工作原理 自动气象观测系统的工作原理相对简单但高效。它首…

真心建议大家都去冲一冲AI产品经理,AI真的能帮你实现职场跃迁

你有没有想过&#xff1a; AI不仅能帮你实现工作提效 还能帮你实现职场跃迁&#xff01; 根据行业报告&#xff0c;近年来AIGC&#xff08;AI Generated Content&#xff09; 领域岗位数量井喷式增长&#xff0c;AI大模型产品经理作为连接技术与市场的桥梁&#xff0c;正扮演…

Git的安装配置

目录 一、git和svn的区别是什么 二、下载Git 三、安装 四、使用 一、git和svn的区别是什么 1、git是分布式的&#xff0c;svn是集中的式的 2、git存储数据时是按元数据的方式存储&#xff0c;而svn是按文件的方式存储 3、git分支和svn的分支不一样 4、git没有全局版本号…

认知战认知作战:萨尔浒之战-努尔哈赤认知作战下的明朝崩溃

认知战认知作战&#xff1a;萨尔浒之战-努尔哈赤认知作战下的明朝崩溃 关键词&#xff1a;萨尔浒战役,后金,努尔哈赤,明朝,认知作战,地形误判,舆论战,军事胜利,盟友支持,内部腐败,认知作战,新质生产力,人类命运共同体,认知战,认知域,认知战研究中心,认知战争,认知战战术,认知战…

雨天道路目标检测数据集(黑夜和白天) 3600张 雨天 带标注 voc yolo 7类

雨天道路目标检测数据集 3600张 雨天 带标注 voc yolo 白天 分类名: (图片张数&#xff0c; 标注个数) car :(1134&#xff0c;10528) truck:(394&#xff0c;722) per son:(387&#xff0c;1585) rider: (47&#xff0c; 56) bike:(64&#xff0c;86) bus:(187&#xff0c; 25…

iOS swift5 苹果app审核被拒 1.4.1

文章目录 1.被拒2. 官网1.4.1的规定3.如何解决参考博客 1.被拒 准则1.4.1-安全-人身伤害 该应用程序连接到外部医疗硬件&#xff0c;以提供医疗服务。然而&#xff0c;为了遵守准则1.4.1&#xff0c;您必须&#xff1a; -提供来自适当监管机构的文件&#xff0c;证明应用程序…

【DataSophon】DataSophon1.2.1 整合Zeppelin并配置Hive|Trino|Spark解释器

目录 ​一、Zeppelin简介 二、实现步骤 2.1 Zeppelin包下载 2.2 work配置文件 三、配置常用解释器 3.1配置Hive解释器 3.2 配置trino解释器 3.3 配置Spark解释器 一、Zeppelin简介 Zeppelin是Apache基金会下的一个开源框架&#xff0c;它提供了一个数据可视化的框架&am…

使用java分别输出二叉树的深度遍历和广度遍历

代码功能 这段Java代码定义了一个二叉树&#xff0c;并实现了两种遍历方法&#xff1a;深度优先搜索&#xff08;DFS&#xff09;和广度优先搜索&#xff08;BFS&#xff09;。通过DFS&#xff0c;代码从根节点开始&#xff0c;优先访问子节点&#xff0c;直至最深的节点&…

气膜体育馆在学校中的应用:创新教育设施的未来—轻空间

随着气膜体育馆的广泛推广&#xff0c;越来越多的学校开始探索其在日常教学和活动中的应用&#xff0c;开创了新的教育模式和学生体验。 提升体能训练与健康教育 气膜体育馆以其卓越的设施条件&#xff0c;为学生的体能训练提供了理想的场所。在这里&#xff0c;专业教练可以为…

理解 ECMAScript 与 JavaScript:标准与实现的区别

文章目录 1.引言 2.ECMAScript 是什么&#xff1f; 3.JavaScript 是什么&#xff1f; 4.ECMAScript 和 JavaScript 的关系 5.ECMAScript 的发展历史 6.JavaScript 的浏览器特性 7.ECMAScript 与 JavaScript 的区别 8.常见误区 9.结语 1.引言 在前端开发的世界中&#…

食品企业为什么要参加第111届深圳秋糖酒会

第111届深圳秋季全国糖酒会将于2024年10月29日至31日在深圳国际会展中心&#xff08;宝安&#xff09;隆重举行&#xff0c;展览规模达28万平方米&#xff0c;刷新了秋季糖酒会的历史纪录。如此宏大的规模&#xff0c;不仅彰显了糖酒会的影响力&#xff0c;也预示着本次展会将汇…

利士策分享,节后重启,再启新程

利士策分享&#xff0c;节后重启&#xff0c;再启新程 随着日历翻过最后一页法定节假日的篇章&#xff0c;我们再次回到了熟悉而繁忙的工作岗位上。 那些与家人团聚的温馨时光&#xff0c;那些悠然自得的休闲日子&#xff0c;仿佛还在眼前&#xff0c;却又已悄然远去。 面对这…

【Golang】关于Go语言中的IO操作

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

基于SpringBoot+Vue的流浪猫狗救助系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

C0022.在Clion中快速生成函数中形参注释及添加函数说明

快速生成函数中形参注释 只需要在函数前输入/**&#xff0c;然后按回车&#xff0c;这样即可快速生成如下函数形参注释。 新增函数描述 在设置界面中的搜索框中输入Code Generation&#xff0c;然后勾选 如下选择框&#xff0c;这样就可以在如上生成的代码快中新增函数描述栏…

从零开始:全面掌握AI大模型的终极学习指南,学废了 我这就去手撕面试官!

学习AI大模型从零基础入门到精通是一个循序渐进的过程&#xff0c;涉及到理论知识、编程技能和实践经验。下面是一份详细的指南&#xff0c;帮助你从头开始学习并逐步掌握AI大模型的构建与应用。 第一阶段&#xff08;10天&#xff09;&#xff1a;初阶应用 该阶段让大家对大…

深入理解Transformer的笔记记录(非小白贴)NNLM → Word2Vec

文章的整体介绍顺序为&#xff1a; NNLM → Word2Vec → Seq2Seq → Seq2Seq with Attention → Transformer → Elmo → GPT → BERT 自然语言处理相关任务中要将自然语言交给机器学习中的算法来处理&#xff0c;通常需要将语言数学化&#xff0c;因为计算机机器只认数学符号…

SDUT数据结构与算法第二次机测

目录 7-1 括号匹配 7-2 后缀式求值 7-3 表达式转换 7-4 【模板】KMP字符串匹配 比较详细注释和图解请看KMP——字符串匹配-CSDN博客&#xff0c;&#xff08;点击链接可跳转&#xff09;一看就会 7-5 约瑟夫环&#xff08;押题&#xff0c;重要&#xff09; 7-6 单调栈&a…