如何找到字符串中最长的重复序列

时间:2015-12-15 15:56:17

标签: ruby string

我在文本文件上有一个长字符串(DNA序列,超过20 000个字符),我正在尝试找到其中重复至少三次的最长序列。实现这一目标的最佳方法是什么?

我能找到的唯一现有主题是在两个或多个单独的字符串中查找重复,但如何使用一个长字符串进行重复?

3 个答案:

答案 0 :(得分:0)

如果我理解正确,您正在寻找解决“最长重复子字符串问题”:https://en.wikipedia.org/wiki/Longest_repeated_substring_problem

看一看 http://rubyquiz.com/quiz153.html

这个宝石可能会帮助您解决问题: https://github.com/luikore/triez

CTRL + F:“解决最长的常见子字符串问题:”

答案 1 :(得分:0)

准确地说,您正在寻找最长的3-fold substring

  

字符串s的k重子串是s的重复子串,在s中出现至少k次

几年前有一个类似的python question会给你很多好消息。具体来看看Finding the Longest Multiple Repeat。有solution on GitHub但它也在Python中。

答案 2 :(得分:0)

str = "ababaeabadefgdefaba"  

案例1:给定长度的子串不能重叠

n = 3
n.times.
  flat_map { |i| str[i..-1].each_char.each_cons(n).to_a }.
  uniq.
  each_with_object({}) do |a,h|
    r = /#{a.join('')}/
    h[a.join('')] = str.scan(r).size
end.max_by { |_,v| v }
  #=> ["aba", 3]

案例2:给定长度的子字符串可以重叠

只需要更改定义正则表达式的行:

n = 3
n.times.
  flat_map { |i| str[i..-1].each_char.each_cons(n).to_a }.
  uniq.
  each_with_object({}) do |a,h|
    r = /#{a.first}(?=#{a.drop(1).join('')})/
    h[a.join('')] = str.scan(r).size
  end.max_by { |_,v| v }
  #=> ["aba", 4]

考虑案例2中执行的步骤:

n = 3
b = n.times
  #=> #<Enumerator: 3:times> 
c = b.flat_map { |i| str[i..-1].each_char.each_cons(n).to_a }
  #=> [["a", "b", "a"], ["b", "a", "b"], ["a", "b", "a"], ["b", "a", "e"],
  #    ["a", "e", "a"], ["e", "a", "b"], ["a", "b", "a"], ["b", "a", "d"],
  #    ["a", "d", "e"], ["d", "e", "f"], ["e", "f", "g"], ["f", "g", "d"],
  #    ["g", "d", "e"], ["d", "e", "f"], ["e", "f", "a"], ["f", "a", "b"],
  #    ["a", "b", "a"], ["b", "a", "b"], ["a", "b", "a"], ["b", "a", "e"],
  #    ["a", "e", "a"], ["e", "a", "b"], ["a", "b", "a"], ["b", "a", "d"],
  #    ["a", "d", "e"], ["d", "e", "f"], ["e", "f", "g"], ["f", "g", "d"],
  #    ["g", "d", "e"], ["d", "e", "f"], ["e", "f", "a"], ["f", "a", "b"],
  #    ["a", "b", "a"], ["a", "b", "a"], ["b", "a", "e"], ["a", "e", "a"],
  #    ["e", "a", "b"], ["a", "b", "a"], ["b", "a", "d"], ["a", "d", "e"],
  #    ["d", "e", "f"], ["e", "f", "g"], ["f", "g", "d"], ["g", "d", "e"],
  #    ["d", "e", "f"], ["e", "f", "a"], ["f", "a", "b"], ["a", "b", "a"]]
d = c.uniq
  #=> [["a", "b", "a"], ["b", "a", "b"], ["b", "a", "e"], ["a", "e", "a"],
  #    ["e", "a", "b"], ["b", "a", "d"], ["a", "d", "e"], ["d", "e", "f"], 
  #    ["e", "f", "g"], ["f", "g", "d"], ["g", "d", "e"], ["e", "f", "a"],
  #    ["f", "a", "b"]] 
e = d.each_with_object({}) do |a,h|
      r = /#{a.first}(?=#{a.drop(1).join('')})/
      puts "  str.scan(#{r.inspect}) = #{str.scan(r)}" if a == d.first
      h[a.join('')] = str.scan(r).size
      puts "  h[#{a.join('')}] = #{h[a.join('')]}" if a == d.first
    end
  #=>   str.scan(/a(?=ba)/) = ["a", "a", "a", "a"]
  #=>   h[aba] = 4
  #=> {"aba"=>4, "bab"=>1, "bae"=>1, "aea"=>1, "eab"=>1, "bad"=>1, "ade"=>1,
  #    "def"=>2, "efg"=>1, "fgd"=>1, "gde"=>1, "efa"=>1, "fab"=>1}
e.max_by { |_,v| v }
  #=> ["aba", 4] 

在计算e时,对于传递给块的d的第一个元素,块变量a等于["a", "b", "a"],而/a(?=ba)/中的正则表达式str.scan(/a(?=ba)/) {1}}匹配astr后面ba的每个(?=ba)$quiz = new Quiz(); $quiz->setTitle('A quiz.'); $quiz->setAuthor('Alexandre'); $quiz->setContent("Blabla…"); $em = $this->getDoctrine()->getManager(); $em->persist($quiz); 是一个积极的前瞻(不是比赛的一部分)。