Руби Самая короткая суперструна

Цель самой короткой общей проблемы суперструн состоит в том, чтобы найти кратчайшую возможную строку, которая содержит каждую строку в данном наборе в качестве подстрок. Я понимаю, что проблема в "NP complete". Но есть приближенные стратегии для этой проблемы. Например, короткие строки

ABRAC
ACADA
ADABR
DABRA
RACAD

Как реализовать кратчайшую общую проблему суперструн, чтобы вывод для приведенных выше строк был ABRACADABRA? Другой пример

Given

fegiach
bfgiak
hfdegi
iakhfd
fgiakhg

строкаbfgiakhfdegiach возможное решение длины 15.

Я хотел бы реализовать это в Ruby, хотя у меня нет углубленного изучения алгоритмов, хотя я работаю над его улучшением.

Наивная жадная реализация будет включать создание массива суффиксов для каждой подстроки

def suffix_tree(string)
  size = string.length
  suffixes = Array.new(size)
  size.times do |i|
    suffixes[i] = string.slice(i, size)
  end
  suffixes
end

#store the suffixes in a hash
#key is a fragment, value = suffixes
def hash_of_suffixes(fragments)
  suffixes_hash = Hash.new
  fragments.each do |frag|
    suffixes_hash["#{frag}"]= suffix_tree(frag)
  end
  suffixes_hash
end


fragments = ['ABRAC','ACADA','ADABR','DABRA','RACAD']
h = hash_of_suffixes(fragments)

#then search each fragment in all the suffix trees and return the number of 
#overlaps for each key

#store the results in graph??
#find possible ordering of the fragments

I would be grateful with some help.

1 ответ

Обратите внимание на комментарий, указывающий на проблемы с вашими примерами. Также обратите внимание, что если есть какой-то хитрый способ сделать это, я не знаю, что это такое. Я просто перебираю все перестановки, соединяю их вместе и нахожу самые короткие.

class ShortestSuperstring
  def initialize(*strings)
    self.strings = strings
  end

  def call
    @result ||= smoosh_many strings.permutation.min_by { |permutation| smoosh_many(permutation.dup).size }
  end

  private

  attr_accessor :strings

  def smoosh_many(permutation, current_word='')
    return current_word if permutation.empty?
    next_word = permutation.shift
    smoosh_many permutation, smoosh_two(current_word, next_word)
  end

  def smoosh_two(base, addition)
    return base if base.include? addition
    max_offset(base, addition).downto 0 do |offset|
      return base << addition[offset..-1] if addition.start_with? base[-offset, offset]
    end
  end

  def max_offset(string1, string2)
    min string1.size, string2.size
  end

  def min(n1, n2)
    n1 < n2 ? n1 : n2
  end
end

И набор тестов:

describe ShortestSuperstring do
  def self.ss(*strings, possible_results)
    example "#{strings.inspect} can come from superstrings #{possible_results.inspect}" do
      result = described_class.new(*strings).call
      strings.each { |string| result.should include string }
      possible_results.should include(result), "#{result.inspect} was not an expected superstring."
    end
  end

  ss '', ['']
  ss "a", "a", "a", ['a']
  ss "a", "b", %w[ab ba]
  ss 'ab', 'bc', ['abc']
  ss 'bc', 'ab', ['abc']
  ss 'abcd', 'ab', ['abcd']
  ss 'abcd', 'bc', ['abcd']
  ss 'abcd', 'cd', ['abcd']
  ss 'abcd', 'a', 'b', 'c', 'd', ['abcd']
  ss 'abcd', 'a', 'b', 'c', 'd', 'ab', 'cd', 'bcd', ['abcd']

  %w[ABRAC ACADA ADABR DABRA RACAD].permutation.each do |permutation|
    ss *permutation, %w[RACADABRAC ADABRACADA]
  end

  %w[fegiach bfgiak hfdegi iakhfd fgiakhg].permutation.each do |permutation|
    ss *permutation, %w[bfgiakhgiakhfdegifegiach
                        bfgiakhgfegiachiakhfdegi
                        iakhfdegibfgiakhgfegiach
                        iakhfdegibfgiakhgfegiach
                        fegiachiakhfdegibfgiakhg
                        fegiachbfgiakhgiakhfdegi
                        iakhfdegifegiachbfgiakhg]
  end
end
Другие вопросы по тегам