快速的字谜解决

时间:2013-03-12 23:04:14

标签: ruby algorithm big-o anagram

鉴于两个字符串,我想确定它们是否是彼此的字谜。以下是我提出的解决方案:

# output messages
def anagram
    puts "Anagram!"
    exit 
end

def not_anagram
    puts "Not an anagram!"
    exit
end

# main method
if __FILE__ == $0
   # read two strings from the command line
   first, second = gets.chomp, gets.chomp

   # special case 1
   not_anagram if first.length != second.length

   # special case 2
   anagram if first == second

   # general case
   # Two strings must have the exact same number of characters in the
   # correct case to be anagrams.
   # We can sort both strings and compare the results
   if first.chars.sort.join == second.chars.sort.join
      anagram
   else
      not_anagram
   end
end

但我认为可能有更好的一个。我分析了这个解决方案的效率,并提出了:

  • chars:将字符串拆分为字符数组O(n)
  • sort:按字母顺序对字符串进行排序,我不知道如何在Ruby中实现排序,但我假设O(n log n),因为这是通常最为人所知的排序效率
  • join:根据字符数组O(n)
  • 构建字符串
  • ==:字符串比较本身必须检查字符串的每个字符2*O(n)

鉴于上述情况,我将整个解决方案的效率分类为O(n log n),因为排序效率最高。有没有比O(n log n)更有效的方法呢?

4 个答案:

答案 0 :(得分:6)

你的大O应该是O(n*lg(n)),因为排序是限制功能。如果你尝试使用非常大的字谜,你会发现O(n)解决方案的性能损失高于预期。

您可以通过比较两个字符映射中的计数来执行O(n)解决方案=>人物数量。

肯定有其他解决方案具有大致相同的复杂性,但我认为你不能提出比O(n)

更快的任何方法。

答案 1 :(得分:3)

计数示例:

def anagram?(str_a, str_b)
  if str_a.length != str_b.length
    false
  else
    counts = Hash.new(0)
    str_a.each_char{ |c| counts[c] += 1 }
    str_b.chars.none?{ |c| (counts[c] -= 1) < 0 }
  end
end

anagram? 'care', 'race'
# => true
anagram? 'cat', 'dog'
# => false

答案 2 :(得分:3)

您可以在O(n+m)中执行此操作,其中m是字母长度

1.创建一个大小等于输入字母大小的数组。

2.初始化数组中的所有值为“0”。

3.扫描第一个输入字符串,为每个字符增加数组中的相应值(如增量数组[0],如果找到字母表中的第一个字母)。

4.对第二个字符串重复相同的操作,但在这种情况下,数组中的值需要递减。

如果数组中的所有值都是'0',则两个字符串是字谜,否则它们不是。

答案 3 :(得分:1)

我需要一些东西来检查字谜,并想出了这个:

def string_to_array(s)
  s.downcase.gsub(/[^a-z]+/, '').split('').sort
end

def is_anagram?(s1, s2)
  string_to_array(s1) == string_to_array(s2)
end

puts is_anagram?("Arrigo Boito",       "Tobia Gorrio")
puts is_anagram?("Edward Gorey",       "Ogdred Weary")
puts is_anagram?("Ogdred Weary",       "Regera Dowdy")
puts is_anagram?("Regera Dowdy",       "E. G. Deadworry")
puts is_anagram?("Vladimir Nabokov",   "Vivian Darkbloom")
puts is_anagram?("Vivian Darkbloom",   "Vivian Bloodmark")
puts is_anagram?("Dave Barry",         "Ray Adverb")
puts is_anagram?("Glen Duncan",        "Declan Gunn")
puts is_anagram?("Damon Albarn",       "Dan Abnormal")
puts is_anagram?("Tom Cruise",         "So I'm cuter")
puts is_anagram?("Tom Marvolo Riddle", "I am Lord Voldemort")
puts is_anagram?("Torchwood",          "Doctor Who")
puts is_anagram?("Hamlet",             "Amleth")
puts is_anagram?("Rocket boys",        "October Sky")
puts is_anagram?("Imogen Heap",        "iMegaphone")