一个 pangrammatic窗口 是一个包含字母的所有26个字母一块较大的文本的字符串。在给出以下文字的情况下,引用维基百科的示例:
我唱歌,以为我唱歌很好。但是他只是以一种非常古怪的表情抬头看着我的脸,说道:“你唱歌多久了,小姐?”
文本中最小的语法窗口是以下字符串:
很好 但他只是带着一个非常古怪的前夫抬头看着我的脸
实际上每个字母至少包含一次。
我的问题是: 给定文本语料库,查找文本中最小的语法窗口的最有效算法是什么?
我已经考虑了一下,并已经提出了以下算法。我强烈认为这些不是最佳选择,但我认为我应该将它们作为起点。
有一个简单的天真算法可以在时间O(n 2)和空间O(1)中运行:对于字符串中的每个位置,从该位置向前扫描并跟踪您看到的字母(也许在位向量中, ,因为只有26个不同的字母,所以需要空格O(1))。找到所有26个字母后,您便拥有从该给定点开始的最短的语法窗口的长度。每次扫描可能花费时间O(n),并且有O(n)次扫描,总共需要O(n 2)时间。
我们还可以使用改进的二进制搜索在时间O(n log n)和空间O(n)上解决此问题。构造26个数组,每个字母对应一个字母,然后按输入顺序将每个字母在输入文本中的位置填充到这些数组中。我们可以通过简单地扫描文本,将每个索引附加到与当前字符相对应的数组上来完成此操作。一旦有了这个,我们就可以在时间O(log n)中找到最短的语法窗口的长度,该长度是从某个索引开始的,方法是在数组中运行26个二进制搜索以查找每个字符最早出现在输入数组中的时间,即或在给定索引之后。这些数字中的最大者为“长杆”字符,该字符出现在字符串的最下方,从而给出语法窗口的终点。
对上述方法的进一步改进是用van Emde Boas树和以前的搜索替换数组和二进制搜索。对于使用O(n)空间使用的O(n log log n)净运行时间,这将创建时间增加到O(n log log n),但将每个搜索时间减少到O(log log n)时间。
有没有更好的算法?
该算法具有O(M)个空间复杂度和O(N)个时间复杂度(时间不取决于字母大小M):
如果存储字符串中的位置而不是字符计数器,则可以稍微改进此算法。在这种情况下,步骤2应该只读取这些位置并将其与当前位置进行比较,而步骤1应该更新这些位置并(大部分时间)搜索文本中的某些字符。