Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
String 寻找最小泛相图窗口的有效算法?_String_Algorithm_Big O - Fatal编程技术网

String 寻找最小泛相图窗口的有效算法?

String 寻找最小泛相图窗口的有效算法?,string,algorithm,big-o,String,Algorithm,Big O,是包含字母表中所有26个字母的较大文本的子字符串。引用维基百科的一个例子,给出以下文本: 我唱歌,觉得我唱得很好;但他只是抬起头来,带着一种非常疑惑的表情看着我的脸,说:“小姐,你唱歌多久了?” 文本中最小的泛语法窗口是以下字符串: g非常好;但他只是抬头看着我的脸,带着一个非常古怪的前男友 每个字母至少包含一次 我的问题是:给定一个文本语料库,在文本中查找最小泛语法窗口的最有效算法是什么? 我已经对此进行了一些思考,并提出了以下算法。我有一种强烈的感觉,这些都不是最佳的,但我想我会发布它们作为

是包含字母表中所有26个字母的较大文本的子字符串。引用维基百科的一个例子,给出以下文本:

我唱歌,觉得我唱得很好;但他只是抬起头来,带着一种非常疑惑的表情看着我的脸,说:“小姐,你唱歌多久了?”

文本中最小的泛语法窗口是以下字符串:

g非常好;但他只是抬头看着我的脸,带着一个非常古怪的前男友

每个字母至少包含一次

我的问题是:给定一个文本语料库,在文本中查找最小泛语法窗口的最有效算法是什么?

我已经对此进行了一些思考,并提出了以下算法。我有一种强烈的感觉,这些都不是最佳的,但我想我会发布它们作为一个起点

有一个简单的朴素算法在时间O(n2)和空间O(1)中运行:对于字符串中的每个位置,从该位置向前扫描并跟踪您看到的字母(可能在位向量中,因为只有26个不同的字母,所以它占用空间O(1))。一旦你找到了所有26个字母,你就有了从给定点开始的最短泛语法窗口的长度。每次扫描可能需要O(n)个时间,并且有O(n)个扫描,总共需要O(n2)个时间

我们还可以使用改进的二进制搜索在时间O(nlogn)和空间O(n)中解决这个问题。构造26个数组,每个字母对应一个,然后按排序顺序将每个字母在输入文本中的位置填充到这些数组中。我们可以通过简单地扫描文本,将每个索引附加到与当前字符对应的数组中来实现这一点。一旦我们有了这个,我们就可以在时间O(logn)中找到从某个索引开始的最短泛语法窗口的长度,方法是在数组中运行26次二进制搜索,以找到每个字符在给定索引处或之后出现在输入数组中的最早时间。这些数字中最大的一个给出了字符串中最下面的“长极”字符,从而给出了pangrammatic窗口的端点。运行此搜索步骤需要O(logn)时间,因为我们必须对字符串中的所有n个字符执行此操作,所以总运行时间为O(nlogn),数组的内存使用率为O(n)

对上述方法的进一步改进是使用和前置搜索替换数组和二进制搜索。这会将创建时间增加到O(n log log n),但会将每次搜索时间减少到O(log n)时间,因为使用O(n)空间的净运行时间为O(n log n)



有什么更好的算法吗?

对于每个字母,都要跟踪最近的发现。无论何时处理信件,都要更新相应的瞄准索引,并计算所有信件的瞄准索引范围(最大最小值)。找到具有最小范围的位置

复杂性O(n)。O(nlog(m))如果考虑字母大小m

,该算法具有O(m)空间复杂度和O(n)时间复杂度(时间不依赖于字母大小m):

  • 推进第一个迭代器并增加每个已处理字母的计数器。当所有26个计数器均为非零时停止
  • 前进第二个迭代器并减少每个已处理字母的计数器。当这些计数器中的任何一个为零时停止
  • 使用迭代器之间的差异来更新迄今为止最好的结果,并继续执行步骤1


  • 如果不存储字符计数器,而是存储字符串中的位置,则该算法可能会有所改进。在这种情况下,第2步应该只读取这些位置并与当前位置进行比较,而第1步应该更新这些位置并(大部分时间)搜索文本中的某些字符。

    +1在发布问题大约五分钟后,我意识到这一解决方案是可能的。若你们制作一个端点的vEB树,你们可以将任意字母m变成O(m+n log m)。回答得很好@ElKamina,我在下面的输入上尝试了你的算法,它没有返回正确的答案。如果我做得不对,有人能解释一下吗。Alphabate:a,b,c输入字符串:aabbabcca瞄准索引:a-:8,b-:5,c-:7范围(最小,最大):(5,7),Ans:bcca,但正确的Ans应为“abc”@Prafulla这是最近的瞄准。当你处理完这封信,在处理完第八封(5,6,8),第九封(9,6,8)之后,它看起来会像(5,6,7)(分别是a,b,c)。@ElKamina我很抱歉我仍然没有收到它。从(9,6,8)中,我们将窗口计算为(6-9),即“bcca”,但最小的窗口是“abc”?@Prafulla您应该跟踪窗口及其长度。在本例中,有三个可能的窗口7:(5,6,7)、8:(5,6,8)、9:(9,6,8)。它们的窗口长度分别为3,4,4。所以最佳的解决方案是7:(5,6,7),也就是你提到的“abc”,我很确定这是可行的,但我不确定我明白为什么这不会无意中跳过一个窗口。你确信这会正确地考虑所有的窗口吗?@ TeMtPyTyPyff,证明非常简单。步骤2的不变量是这样一个事实:从第二个迭代器开始的最短泛语法窗口的长度正好是(第一个迭代器-第二个迭代器),因为递减第一个迭代器会从集合中删除一个字符。所以你可以把这个算法看作是你的n^2算法的优化变体。这个O(n)是什么,它怎么不依赖于字母表的大小M?具体来说,如何检查O(1)中的“当所有26个计数器都非零时停止”(因为它是常数,所以可以在O(1)中进行检查,但对于一般情况下的M?)@kolistivra:需要一个额外的计数器,每次M个计数器变为非零时,该计数器都会增加。此单个计数器可与O(1)时间内的M进行比较。至于整体复杂度,每个迭代器都要提前O(N)次,每个迭代需要O(1)次才能完成,所以我们需要