草庐IT

java - LCP如何帮助查找模式的出现次数?

coder 2023-08-27 原文

我已经读过最长公共(public)前缀(LCP)可用于查找字符串中某个模式出现的次数。

具体来说,您只需要创建文本的后缀数组,对其进行排序,然后无需进行二进制搜索来找到范围,从而可以计算出出现的次数,则只需为文本中每个连续的条目计算LCP后缀数组。

尽管使用二进制搜索来查找模式的出现次数很明显,但我无法弄清楚LCP如何在这里帮助找到发生次数。

例如,banana的后缀数组:

LCP  Suffix entry
N/A  a  
1    ana  
3    anana  
0    banana  
0    na  
2    nana  

LCP如何帮助找到像“香蕉”或“na”之类的子字符串出现的次数对我来说并不明显。

是否有帮助弄清楚LCP在这里有什么帮助?

最佳答案

我不知道使用LCP数组而不执行二进制搜索的任何方法,但是我相信您所指的是Udi Manber和Gene Myers在Suffix arrays: a new method for on-line string searches中描述的技术。

(注意:以下说明已复制到2014年4月9日的Wikipedia文章中,请参见diff。如果您在此处和Wikipedia上查看修订历史,则会发现此处的修订是第一个编写的。请不要插入诸如“取自Wikipedia”之类的评论添加到我的答案中。)

这个想法是这样的:为了找到在文本T(长度N)中给定字符串P(长度m)的出现次数,

  • 您对T的后缀数组使用二进制搜索(就像您建议的那样)
  • 但是您可以使用LCP数组作为辅助数据结构来加快的速度。更具体地说,您将生成LCP阵列的特殊版本(以下将其称为LCP-LR)并使用它。

  • 使用标准二进制搜索(不提供LCP信息)的问题是,在中,您需要进行每个O(log N)比较,将P与后缀数组的当前条目进行比较,这意味着完整字符串比较,最多m个字符。因此复杂度为O(m * log N)。

    LCP-LR阵列可以通过以下方式将其提高到O(m + log N):
  • 在二进制搜索算法的任何时候,您都像往常一样考虑后缀数组的范围(L,...,R)及其中心点M,并确定是否在左侧子范围中继续搜索(L,...,M)或在右子范围(M,...,R)中。
  • 为了做出决定,将P与M处的字符串进行比较。如果P与M相同,则可以完成,但如果不相同,则将比较P的前k个字符,然后确定P在字典上是否较小或大于M。我们假设结果是P大于M。
  • 因此,在下一步 中,考虑(M,...,R)和中间的新中心点M':
                  M ...... M' ...... R
                  |
           we know:
              lcp(P,M)==k
    

    技巧现在是对LCP-LR进行了预先计算,以便通过O(1)查找可以告诉您M和M'的最长公共(public)前缀lcp(M,M')。

    您已经知道(从上一步开始)M本身与P共同具有k个字符的前缀:lcp(P,M)= k。现在有三种可能性:
  • 情况1:k
  • 情况2:k> lcp(M,M'),即P与M共有的前缀字符多于M与M'共有的前缀字符。因此,如果我们将P与M'进行比较,则公共(public)前缀将小于k,而M'在字典上大于P,因此,在没有进行实际比较的情况下,我们继续左半部分(M,.. 。,M')。
  • 情况3:k == lcp(M,M')。因此,M和M'在前k个字符中都与P相同。要确定我们是继续左半边还是右半边,只需从第(k + 1)个字符开始将P与M'比较即可。
  • 我们以递归方式继续。

  • 总体效果是没有将P的任何字符与文本的任何字符进行多次比较。字符比较的总数以m为界,因此总复杂度确实为O(m + log N)。

    显然,剩下的关键问题是我们如何预先计算LCP-LR,以便它能够在O(1)时间告诉我们后缀数组的任意两个条目之间的lcp?如您所说,标准LCP数组仅告诉您连续条目lct的lct ,即任何x的lcp(x-1,x)。但是,上面描述中的M和M'不一定是连续的条目,那么该怎么做?

    这样做的关键是要认识到在二进制搜索过程中只会出现某些范围(L,...,R):它始终以(0,...,N)开头,并在中心进行除法,然后继续向左或向右继续,然后再将其一半除以此类推。如果考虑到这一点:在二进制搜索过程中,后缀数组的每个条目都恰好是一个可能范围的中心点。因此,恰好有N个不同的范围(L ... M ... R)可能在二分查找中起作用,对于这N个可能的范围,预先计算lcp(L,M)和lcp(M,R)就足够了范围。因此,这是2 * N个不同的预先计算的值,因此LCP-LR的大小为O(N)。

    此外,有一个简单的递归算法可以从标准LCP数组计算O(N)时间中LCP-LR的2 * N值–如果您需要对此进行详细说明,建议您提出一个单独的问题。

    总结一下:
  • 可以根据LCP
  • 在O(N)时间和O(2 * N)= O(N)空间中计算LCP-LR
  • 在二进制搜索过程中使用LCP-LR有助于将搜索过程从O(M * log N)加速到O(M + log N)
  • 根据您的建议,可以使用两个二进制搜索来确定P的匹配范围的左端和右端,并且匹配范围的长度与P的出现次数相对应。

  • 关于java - LCP如何帮助查找模式的出现次数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11373453/

    有关java - LCP如何帮助查找模式的出现次数?的更多相关文章

    1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

      我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

    2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

      总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

    3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

      关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

    4. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

      给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

    5. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

      我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

    6. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

      我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

    7. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

      我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

    8. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

      我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

    9. ruby - 如何指定 Rack 处理程序 - 2

      Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

    10. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

      在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

    随机推荐