在数组中搜索单词

时间:2012-11-10 21:54:34

标签: java arrays string search boggle

  

可能重复:
  How to find list of possible words from a letter matrix [Boggle Solver]

我有一个String[][]数组,例如

h,b,c,d
e,e,g,h
i,l,k,l
m,l,o,p

我需要将ArrayList与此数组匹配,以查找ArrayList中指定的单词。在搜索单词hello时,我需要获得肯定匹配和字母的位置,例如在这种情况下(0,0)(1,1)(2,1),{{1 }和(3,1)

当逐字逐句地发送并且我们假设我们成功找到第一个(3,2)字母时,程序应该尝试在其旁边的位置找到下一个字母(l)。所以它应该与e,e,g,k,o,l,m和i匹配,意味着它周围的所有字母:水平,垂直和对角线。在单词中找不到相同的位置两次,因此l(0,0)(1,1)(2,1)(2,1)是不可接受的,因为位置(3,2)匹配两次。在这种情况下,两者都会匹配单词,因为允许对角位置,但由于要求位置不能多次使用,因此需要匹配另一个(2,1)

此案例也应该匹配

l

如果我们假设我们尝试搜索h,b,c,d e,e,g,h l,l,k,l m,o,f,p ,则无法匹配。 helllo(x1, y1) (x1, y1)无法匹配。

我想知道实现此类功能的最佳方法是什么。如果我在ArrayList中有4x4 (x1, y1) (x2, y2) (x1, y1)数组和10万个单词,那么最有效和最简单的方法是什么?

4 个答案:

答案 0 :(得分:2)

我认为您可能会花费大部分时间来尝试匹配网格无法构建的单词。所以,我要做的第一件事是尝试加快这一步,这应该可以让你在那里大部分时间。

我会将网格重新表达为您按字母索引的可能移动的表格。首先为每个字母分配一个数字(通常是A = 0,B = 1,C = 2,......等等)。对于你的例子,让我们使用你所拥有的字母的字母表(在最后一行显示为“m o f p”的第二个网格中):

 b | c | d | e | f | g | h | k | l | m |  o |  p
---+---+---+---+---+---+---+---+---+---+----+----
 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11

然后你创建一个2D布尔数组,告诉你是否有一个可用的字母转换:

     |  0  1  2  3  4  5  6  7  8  9 10 11  <- from letter
     |  b  c  d  e  f  g  h  k  l  m  o  p
-----+--------------------------------------
 0 b |     T     T     T  T     
 1 c |  T     T  T     T  T
 2 d |     T           T  T
 3 e |  T  T     T     T  T  T  T
 4 f |                       T  T     T  T
 5 g |  T  T  T  T        T  T  T
 6 h |  T  T  T  T     T     T  T
 7 k |           T  T  T  T     T     T  T
 8 l |           T  T  T  T  T  T  T  T  T
 9 m |                          T     T
10 o |              T        T  T  T
11 p |              T        T  T
 ^
 to letter

现在浏览你的单词列表并将单词转换为过渡(你可以预先计算出来):

hello (6, 3, 8, 8, 10):
6 -> 3, 3 -> 8, 8 -> 8, 8 -> 10

然后在表格中查看是否允许这些转换:

[6][3] : T
[3][8] : T
[8][8] : T
[8][10] : T

如果他们都被允许,那么可能会找到这个词。

例如,可以在第4次转换(m到e:helMEt)中排除单词“helmet”,因为表中的该条目为false。

可以排除hamster这个词,因为不允许第一个(h到a)转换(甚至不存在于你的表中)。

现在,对于你没有消除的其余单词,尝试在网格中实际找到它们的方式,就像你现在这样做或者在这里的其他一些答案中所建议的那样。这是为了避免因网格中相同字母之间的跳转而导致误报。例如,表格允许使用“帮助”一词,但不允许使用“帮助”一词

让我知道您的boggle手机应用程序何时完成! ;)

答案 1 :(得分:0)

一种研究方法是从网格中生成所有可能的字母(字符串)序列,然后检查这组字符串中是否存在每个单词,而不是根据网格检查每个单词。例如。从第一个网格中的h开始:

h
hb
he
he // duplicate, but different path
hbc
hbg
hbe
hbe // ditto
heb
hec
heg
...

由于生成序列的开销,这对于非常大的单词列表来说可能更快。对于小的单词列表,可以更快地针对网格单独测试它们。

您可能需要存储整个路径(包括坐标),或者有一个单独的步骤来计算匹配单词的路径。哪个更快将取决于命中率(即您在网格中实际找到的输入字的比例)。

根据您需要实现的目标,您可以将序列与字典单词列表进行比较,以便在开始匹配之前消除非单词。

linked question中有

更新2 ,有几种工作的快速解决方案可以从网格生成序列,递归加深以生成更长的序列。然而,他们针对从单词列表生成的Trie测试这些,这使得他们能够尽早放弃序列的子树 - 这会修剪搜索并大大提高效率。这与Markus建议的过渡过滤具有类似的效果。

答案 2 :(得分:0)

虽然我确信在学术上对这个问题有一个美好而有效的答案,但你可以使用相同的方法,但有一个列表可能性。因此,对于“你好”这个词,当你找到字母'h'时,接下来你将添加可能的'e'字母,依此类推。每种可能性都会形成一个字母路径。

答案 3 :(得分:0)

我首先将您的网格视为一个图形,其中每个网格位置都是一个节点,每个节点都连接到它的八个邻居(但是,您不需要在代码中将其显式编码为图形)。一旦找到潜在的起始字母,您需要做的就是从每个起始位置进行深度优先搜索。关键是要记住你已经搜索过的地方,这样你就不会为自己做更多的工作(或者更糟糕的是,陷入困境)。


根据所使用的字符空间的大小,您也可以从构建查找表中受益。我们假设英语(26个连续的字符代码点);如果您从构建一个26个元素的List<Point>[]数组开始,您可以从网格中填充一次该数组,然后可以快速获取一个位置列表以开始搜索任何单词。例如,要获取h的位置,我会写arr['h'-'a']

如果您应用相同的策略并为图中的每个边列表构建查找表,您甚至可以进一步利用这一点。您不必搜索每个节点的所有8条边,而是已知道要搜索的边(如果有)。

(注意 - 如果您的角色空间不连续,您仍然可以执行查找表,但您需要使用HashMap<Character,List<Point>>map.get('h')代替。)