在字母矩阵中查找国家名称

时间:2017-11-09 21:30:15

标签: python python-2.7

我的五年级女儿为她的家庭工作寻求帮助。在10x10矩阵中,找到9个国家/地区名称。我认为计算机可以在没有所有答案的情况下尝试半小时后做得更好。这就是我做的。但它只找到7个国家。第八个是英格兰,在国家名单中被命名为不同。最后一个在哪里?此脚本效率也非常低,因为它使用重复元素多次搜索国家/地区列表。我找到了这个boggle solver post,它正在处理更复杂的案例。它提到了" trie"数据结构可以有效地解决这类问题。任何人都可以详细说明细节吗?提前谢谢,

#!/usr/bin/env python
import numpy as np
import re
import os

B = [['k','l','m','a','l','t','a','l','b','s'],
     ['i','e','n','y','e','j','i','i','y','r'],
     ['o','r','o','h','w','d','r','z','u','i'],
     ['c','o','r','v','m','z','t','a','i','l'],
     ['i','p','w','b','j','q','s','r','d','a'],
     ['x','a','a','d','n','c','u','b','f','n'],
     ['e','g','y','e','h','i','a','h','w','k'],
     ['m','n','g','a','k','g','f','d','s','a'],
     ['g','i','d','n','a','l','g','n','e','y'],
     ['b','s','t','r','f','g','s','a','i','u']]
Matrix=np.matrix(B)
Shape=Matrix.shape
row = Shape[0]-1
col = Shape[1]-1
wordlist = []
DIRECTIONS = [ (-1,-1), (0,-1), (1,-1),(-1,0),(1,0),(-1,1),(0,1),(1,1)]

def expand(i,j,xd,yd):
#every time expand to one direction based on passed in variable
    if ( i+xd >= 0 and i+xd <= row and j+yd >= 0 and j+yd <= col ):
        wordlist.append(wordlist[-1] + Matrix[i+xd,j+yd])
        expand(i+xd,j+yd,xd,yd)

print 'matrix is {} x{:2}'.format(Shape[0],Shape[1])
for i in range(Shape[0]):
    for j in range(Shape[1]):
        for xd,yd in DIRECTIONS:
#before extend to each direction, should set last element as current position letter
# country name is from http://www.countries-list.info/Download-List
            wordlist.append(Matrix[i,j])
            expand(i,j,xd,yd)

for word in wordlist:
# tried to regex to search file, but it is slow comparing to system grep command
        if len(word) > 1 and  ( not os.system("grep -iw " + word + " /home/cmaaek/Downloads/list.txt > /dev/null")):
            print(word)

2 个答案:

答案 0 :(得分:1)

一个特里(发音为&#34; 尝试&#34;)是一个如下所示的数据结构:

Figure 1. Diagram of a Trie

trie中的每个路径对应一个不同的单词。在上面的trie中,观察您可以沿着任何路径追踪以形成有效的单词。这是通过让两个节点共享父节点(如果它们在特定位置共享一个字母)来构造的。所以,对于&#34; NEWS&#34;和&#34; NOT&#34;,每个单词的第一个位置的字符是相同的 - 这就是为什么他们共享节点&#34; N&#34;在图中。但是,每个单词的第二个字符是&#34; E&#34;和&#34; O&#34;它们分别是不同的,因此它们分支成不同的路径。每个节点还有一个指示器,告诉您它是否对应于单词的结尾(图中未显示)。

这是有效的原因是因为它是一种非常紧凑/有效的方式来表示字典。它还允许我们快速确定查询单词是否在我们的字典中,因为我们每次只需要向下一条路径来确定单词是否在我们的字典中。

您可以从国家/地区名称列表中构建特里结构,然后,您可以使用特里结构查询电路板上的国家/地区名称。例如,如果您正在寻找&#34; Video&#34;在我上面给出的trie图中,然后你将返回False,因为没有起始节点(A,D,N,Z)与第一个字符V匹配。如果第一个字符匹配,那么你检查是否有任何子节点匹配下一个字符,依此类推。这使您可以在从填字游戏板中的某个起始角色搜索时快速消除选项。

作为另一种优化,您可能希望记录导致死胡同的填字游戏板位置(即无法从该位置形成有效的国家/地区名称)。这样您就可以避免查看无法帮助您找到解决方案的董事会职位,这也可以加快您的代码速度。希望这可以帮助!

答案 1 :(得分:1)

这是一个trie python实现,它在一个如此小的网格上比字符串暴力更慢:

B = [['k','l','m','a','l','t','a','l','b','s'],
     ['i','e','n','y','e','j','i','i','y','r'],
     ['o','r','o','h','w','d','r','z','u','i'],
     ['c','o','r','v','m','z','t','a','i','l'],
     ['i','p','w','b','j','q','s','r','d','a'],
     ['x','a','a','d','n','c','u','b','f','n'],
     ['e','g','y','e','h','i','a','h','w','k'],
     ['m','n','g','a','k','g','f','d','s','a'],
     ['g','i','d','n','a','l','g','n','e','y'],
     ['b','s','t','r','f','g','s','a','i','u']]

方式:

way={}
A=way[1,0]=sum(B,[])
way[0,1]=sum((A[i::10] for i in range(10)),[])
way[1,1]=(A*11)[::11]
way[-1,1]=(A*9)[::9]
ways='|'.join([''.join(l) for  l in way.values()])    
ways+= '|'+ ways[::-1]
#countries=['afghanistan',....,'england;), ...

蛮力:

# In [26]: [w for w in countries if w in ways]
# Out[26]: ['austria', 'brazil', 'chad', 'england', 'malta',\
# 'mexico', 'norway', 'singapore']
# 
# In [27]: %timeit [w for w in countries if w in ways]
# 238 µs ± 7.21 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
# 

特里:

from collections import defaultdict
trie = lambda : defaultdict(trie) 

def add(country,root):
    t=root
    for l in country: t=t[l]
    t[''] = country

countrie = trie()
for c in countries : add(c,countrie)  

def find(trie,way):
    for i in range(len(way)):
        t=trie
        for l in way[i:]:
            if l in t:
                t=t[l]
                if '' in t : yield t['']
            else: break


# In [28]: list(find(countrie,ways))
# Out[28]: 
# ['malta', 'norway', 'chad', 'brazil', 'austria',\
#  'singapor, 'mexico', 'england']
# 
# In [29]: %timeit list(find(countrie,ways))
# 457 µs ± 9.22 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)            

修改

来自here的370k英语单词词典,蛮力需要412毫秒 找到496个单词。 Trie技术速度提高了500倍,仅需900μs,即使创建成本为600ms;但你必须只建一次。