假设dict 是您的字典中的字符串数组,scrambled 是打乱的单词(字符串)。考虑到scrambled 的所有排列或(更糟)dist 的元素将非常低效。例如,假设一个加扰排列的前两个字母是qz。如果dict 中没有以qz 开头的元素(单词),那么考虑以qz 开头的scrambled 的任何排列都是没有意义的。
数据结构
假设这是我们的字典。
dict = ["dog", "cat", "cow", "emu", "cod", "cobra"]
如果我们只想查看字典中是否有几个打乱的单词,我们可以对每个单词都这样做:
r = 'mue'.split('').permutation(3).find { |w| dict.include?(w.join) }
#=> ["e", "m", "u"]
r.any? ? r.join('') : nil
#=> "emu"
r = 'nvwls'.split('').permutation(3).find { |w| dict.include?(w.join) }
#=> nil
更有趣的问题是如何以更有效的方式执行此操作,以检查具有许多排列的大量可能较长的单词。
第一步是重新组织字典以提高查找效率。我不是建议如何做到这一点的最佳人选,因为我不熟悉计算机科学的那个(或任何其他)分支。这是一种使用多级哈希的方法:
dh = { "c"=>{ "a"=>{ "t"=>nil },
"o"=>{ "b"=>{ "r"=>{ "a"=>nil } }, "w"=>nil, "d"=>nil } },
"d"=>{ "o"=>{ "g"=>nil } },
"e"=>{ "m"=>{ "u"=>nil } } }
dh["c"]“包含”所有以“c”开头的单词; dh["c"]["a"] 包含所有以“ca”开头的单词,依此类推。 dh["c"]["a"]["t"] => nil 表示dh["c"]["a"]["t"].join('') => 'cat' 是字典中的单词之一。我假设你有dh。如果您想获得有关如何从 dict 构造 dh 的建议,也许您可以将其作为一个单独的问题提出。
代码
这是一种(递归)方法,可用于查看scrambled 的任何解扰是否包含在dict 中。 (修改它以编译在dict 中找到的所有排列的列表并不难,但这不是我解决的问题。)这个方法是用look_up(dh, scrambled) 调用的。
def look_up(dh, left, used = '')
left.size.times do |i|
left_copy = left.dup
e = left_copy[i]
left_copy[i] = ''
v = dh[e]
case v
when nil
(return used + e) if left_copy.empty?
when Hash
word = look_up(v, left_copy, used + e)
return word if word
end
end
nil
end
示例
look_up(dh, "owc") #=> "cow"
look_up(dh, "mue") #=> "emu"
look_up(dh, "bocar") #=> "cobra"
look_up(dh, "esuomhcruhc") #=> nil
说明
假设dh 同上,scrambled => "owc"。那么
left = "owc"
used = ''
left.size #=> 3
enum = left.size.times #=> #<Enumerator: 3:times>
我们可以将enum 转换为一个数组,看看它将传递给它的块:
enum.to_a #=> [0, 1, 2]
最初,块变量i 设置为0 和
left_copy = left.dup #=> "owc"
e = left_copy[i] #=> left_copy[0] => "o"
left_copy[i] = '' #left_copy[i] = ''
left_copy #=> "wc"
v = dh[e] #=> v = dh[0] => nil
dh[0] => nil,结合left_copy.empty? => false,表示字典中没有以'o'开头的单词,所以我们回到循环顶部并设置i => 1,并考虑以'o'开头的单词:
left_copy = left.dup #=> "owc"
e = left_copy[i] #=> left_copy[1] => "w"
left_copy[i] = '' #=> left_copy[1] = ''
left_copy #=> "oc"
v = dh[e] #=> v = dh[1] => nil
字典中没有以'w'开头的单词,所以我们用i => 2再次循环,
searching for words in the dictionary beginning with `'c'`:
e = left_copy[2] #=> "c"
left_copy[2] = '' #=> left_copy[2] = ''
left_copy #=> "ow"
v = dh[2] #=> {"a"=>{"t"=>nil},
# "o"=>{"b"=>{"r"=>{"a"=>nil}}, "w"=>nil, "d"=>nil}}
这表明字典中有以'ca`` and'co'`开头的单词。
由于v是一个哈希,我们递归调用该方法
word = look_up(v, left_copy, used + e)
# look_up({"a"=>{"t"=>nil},
# "o"=>{"b"=>{"r"=>{"a"=>nil}}, "w"=>nil, "d"=>nil}},
# "ow",
# "c")
其他字母的计算过程类似。当发现字典中有字符串"co"表示的单词时:
{ "b"=>{ "r"=>{ "a"=>nil } }, "w"=>nil, "d"=>nil }
我们得出结论,因为这个哈希包含"w"=>nil,所以"cow"在字典中,所以我们在递归链上返回'cow'并完成。