确定集合中是否存在前缀

时间:2011-03-23 07:31:01

标签: ruby algorithm string

给定一组字符串,例如:

"Alice"
"Bob"
"C"
"Ca"
"Car"
"Carol"
"Caroling"
"Carousel"

并给出一个字符串,说:

"Carolers"

我想要一个返回数组内部最小前缀的函数。

对于上面的例子,函数应该返回:“Caro”。 (随后的电话将返回“Carole”)

我是Ruby的新手,虽然我可能会破解一些丑陋的东西(使用我的C / C ++ / Objective-C大脑),但我想学习如何正确(优雅地?)编写代码。

6 个答案:

答案 0 :(得分:5)

Ruby中有一个名为Abbrev的神奇模块。

require 'abbrev'

abbreviations = Abbrev::abbrev([
  "Alice",
  "Bob",
  "C",
  "Ca",
  "Car",
  "Carol",
  "Caroling",
  "Carousel"
])
carolers = Abbrev::abbrev(%w[Carolers])
(carolers.keys - abbreviations.keys).sort.first # => "Caro"

上面我拿了第一个元素,但这显示了还有什么可用。

pp (carolers.keys - abbreviations.keys).sort 
# >> ["Caro", "Carole", "Caroler", "Carolers"]

在函数中包装所有上述内容,计算生成的缺失元素,然后迭代它们,将它们放到一个块中,或者使用枚举器逐个返回它们。

这是为单个单词生成的内容。对于数组来说,它更复杂。

require 'pp'
pp Abbrev::abbrev(['cat'])
# >> {"ca"=>"cat", "c"=>"cat", "cat"=>"cat"}

pp Abbrev::abbrev(['cat', 'car', 'cattle', 'carrier'])
# >> {"cattl"=>"cattle",
# >>  "catt"=>"cattle",
# >>  "cat"=>"cat",
# >>  "carrie"=>"carrier",
# >>  "carri"=>"carrier",
# >>  "carr"=>"carrier",
# >>  "car"=>"car",
# >>  "cattle"=>"cattle",
# >>  "carrier"=>"carrier"}

答案 1 :(得分:3)

您的问题仍然与您期望的结果不符。您似乎需要前缀,而不是子串(因为"a"将是数组中尚未存在的最短子串)。要搜索前缀,这应该足够了:

array = [
"Alice",
"Bob",
"C",
"Ca",
"Car",
"Carol",
"Caroling",
"Carousel",
]

str = 'Carolers'

(0..str.length).map{|i|
  str[0..i]
}.find{|s| !array.member?(s)}

答案 2 :(得分:0)

我不是Ruby专家,但我认为您可能希望通过将您的集转换为trie来解决此问题。一旦你构建了trie,你的问题就可以简单地从trie的根部向下走,沿着单词中所有字母的边缘,直到你找到一个没有标记为单词或走路的节点。脱掉了特里。在任何一种情况下,您都找到了一个不属于任何单词的节点,并且您所拥有的单词的最短前缀在该集合内部尚不存在。此外,这将允许您快速运行任意数量的前缀检查,因为在您构建了trie之后,算法在字符串的长度上花费的时间最多是线性的。

希望这有帮助!

答案 3 :(得分:0)

我不确定你要求的是什么,而不是一些Ruby代码的例子来找到公共前缀。我假设你想找到最小的字符串,它是给定集合中字符串数最多的前缀。这是一个示例实现:

class PrefixFinder
  def initialize(words)
    @words = Hash[*words.map{|x|[x,x]}.flatten]
  end
  def next_prefix
    max=0; biggest=nil
    @words.keys.sort.each do |word|
      0.upto(word.size-1) do |len|
        substr=word[0..len]; regex=Regexp.new("^" + substr)
        next if @words[substr]
        count = @words.keys.find_all {|x| x=~regex}.size
        max, biggest = [count, substr] if count > max
        #puts "OK: s=#{substr}, biggest=#{biggest.inspect}"
      end
    end
    @words[biggest] = biggest if biggest
    biggest
  end
end

pf = PrefixFinder.new(%w(C Ca Car Carol Caroled Carolers))
pf.next_prefix # => "Caro"
pf.next_prefix # => "Carole"
pf.next_prefix # => "Caroler"
pf.next_prefix # => nil

没有评论此代码的性能(或正确性),但它确实显示了一些Ruby习语(实例变量,迭代,散列等)。

答案 4 :(得分:0)

  => inn = ["Alice","Bob","C","Ca","Car","Carol","Caroling","Carousel"]
  => y = Array.new
  => str="Carolers"

将给定的字符串拆分为数组

  => x=str.split('')
  # ["C","a","r","o","l","e","r","s"] 

形成所有组合

  => x.each_index {|i| y << x.take(i+1)}
  # [["c"], ["c", "a"], ["c", "a", "r"], ["c", "a", "r", "o"], ["c", "a", "r", "o", "l"], ["c", "a", "r", "o", "l", "e"], ["c", "a", "r", "o", "l", "e", "r"], ["c", "a", "r", "o", "l", "e", "r", "s"]]

使用Join连接

  => y =  y.map {|s| s.join }
  # ["c", "ca", "car", "caro", "carol", "carole", "caroler", "carolers"]

从y中选择输入数组中不可用的第一项

  => y.select {|item| !inn.include? item}.first

您将获得&#34; caro&#34;

汇总所有

 def FindFirstMissingItem(srcArray,strtocheck)
   y=Array.new
   x=strtocheck.split('')
   x.each_index {|i| y << x.take(i+1)}
   y=y.map {|s| s.join}
   y.select {|item| !srcArray.include? item}.first
 end

并致电

 => inn = ["Alice","Bob","C","Ca","Car","Carol","Caroling","Carousel"]
 => str="Carolers"

 FindFirstMissingItem inn,str

答案 5 :(得分:0)

非常简单的版本(但不是非常Rubyish):

str = 'Carolers'
ar = %w(Alice Bob C Ca Car Carol Caroling Carousel)

substr = str[0, n=1]
substr = str[0, n+=1] while ar.include? substr
puts substr