假设您有一个包含有效单词的字典。
给定一个删除了所有空格的输入字符串,确定该字符串是否由有效单词组成。
您可以假设字典是提供O(1)查找的哈希表。
Some examples:
helloworld-> hello world (valid)
isitniceinhere-> is it nice in here (valid)
zxyy-> invalid
如果一个字符串有多个可能的解析,只需返回true即可。
字符串可能很长。因此,想一个兼顾空间和算法的算法。时间有效。
答案 0 :(得分:6)
我认为所有字符串的集合作为有效单词的连接(从有限字典中取出的单词)形成了字符字母表上的常规语言。然后,您可以构建一个完全接受所需字符串的有限自动机;计算时间是O(n)。
例如,让字典由单词{bat,bag}组成。然后我们构造以下自动机:状态用0,1,2表示。边缘:(0,1,b),(1,2,a),(2,0,t),(2,0,g) ;其中三元组(x,y,z)表示在输入z上从x到y的边缘。唯一接受状态为0.在每个步骤中,在读取下一个输入符号时,您必须计算该输入可达的状态集。鉴于自动机中的状态数是恒定的,这是复杂度O(n)。至于空间复杂性,我认为你可以用O(字数)和上面的构造提示。
对于另一个例子,使用单词{bag,bat,bun,but},自动机将如下所示:
假设已经构建了自动机(执行此操作的时间与单词的长度和数量有关:-)我们现在认为决定自动机是否接受字符串的时间是O( n)其中n是输入字符串的长度。 更正式地说,我们的算法如下:
现在,这个循环的执行次数和输入符号一样多。我们唯一要检查的是步骤3和5需要不断的时间。假设S和R的大小不大于自动机中的状态数,这是常数,并且我们可以以查找时间恒定的方式存储边缘,接下来是这样。 (请注意,我们当然会丢失多个'解析',但这也不是必需的。) 我认为这实际上被称为常规语言的成员问题,但我找不到合适的在线参考。
答案 1 :(得分:0)
我会选择带隐式回溯的递归算法。功能签名:f: input -> result
,input
为字符串,result
为true
或false
,具体取决于整个字符串是否可以正确标记。
像这样工作:
input
为空字符串,请返回true
。input
的长度为一的前缀(即第一个字符)。如果它在字典中,请在后缀f
上运行input
。如果返回true
,也请返回true
。f
的调用返回false
,则将前缀加长一,并在步骤2重复。如果不能再生成前缀(已经在字符串的末尾),请返回false
。对于具有低到中等量的模糊前缀的词典,这个应该在实践中获得相当好的运行时间(在一般情况下为O(n),我会说),尽管在理论上,可能构建具有O(2 ^ n)复杂度的病理病例。然而,我怀疑我们可以做得更好,因为我们无论如何都需要回溯,所以使用传统预先计算的词法分析器的“本能”O(n)方法是不可能的。 ......我想。
编辑:平均案例复杂度的估算可能不正确,请参阅我的评论。
空间复杂性只是堆栈空间,所以即使在最坏的情况下也是O(n)。