Algorithm 每个字符出现偶数次(可能为零)的最长子字符串
假设我们有一个字符串Algorithm 每个字符出现偶数次(可能为零)的最长子字符串,algorithm,computer-science,Algorithm,Computer Science,假设我们有一个字符串s。我们希望找到s中最长子字符串的长度,以便子字符串中的每个字符出现偶数次(可能为零)。 WC时间:O(nlgn)。厕所空间:O(n) 首先,很明显,子字符串的长度必须是偶数。其次,我熟悉滑动窗口方法,其中我们锚定一些右索引,并寻找最左边的索引以符合您的标准。我试着在这里应用这个想法,但无法真正表达出来 此外,在我看来,优先级队列可能会派上用场(因为O(nlgn)要求在某种程度上暗示了这一点) 我很高兴能得到帮助 让我们定义以下位集: B[c,i] = 1 if charac
s
。我们希望找到s
中最长子字符串的长度,以便子字符串中的每个字符出现偶数次(可能为零)。WC时间:
O(nlgn)
。厕所空间:O(n)
首先,很明显,子字符串的长度必须是偶数。其次,我熟悉滑动窗口方法,其中我们锚定一些右
索引,并寻找最左边的索引以符合您的标准。我试着在这里应用这个想法,但无法真正表达出来
此外,在我看来,优先级队列可能会派上用场(因为O(nlgn)
要求在某种程度上暗示了这一点)
我很高兴能得到帮助 让我们定义以下位集:
B[c,i] = 1 if character c appeared in s[0,...,i] even number of times.
计算B[c,i]
需要线性时间(对于所有值):
由于字母表的大小是恒定的,所以位集也是恒定的(对于每个i
)
请注意,条件:
子字符串中的每个字符出现偶数次
对于子串s[i,j]
当且仅当索引i
的位集与索引j
的位集相同时为真(否则,此子串中有一个位重复奇数次;另一个方向:如果有一个位重复多次,则其位不能相同)
因此,如果我们将所有位集存储在某个集合(哈希集合/树集合)中,并且只保留最新的条目,则此预处理需要O(n)
或O(nlogn)
时间(取决于哈希/树集合)
在第二次迭代中,对于每个索引,找到具有相同位集的较远索引(O(1)/O(logn)
,具体取决于哈希/树集),找到子字符串长度,并将其标记为候选。最后,选择最长的候选人
此解决方案是位集的O(n)
空间和O(n)/O(nlogn)
时间,具体取决于是否使用哈希/树解决方案
伪代码:
def NextBitset(B, c): # O(1) time
for each x in alphabet \ {c}:
B[x, i] = B[x, i-1]
B[c, i] = B[c, i-1] XOR 1
for each c in alphabet: # O(1) time
B[c,-1] = 0
map = new hash/tree map (bitset->int)
# first pass: # O(n)/O(nlogn) time
for i from 0 to len(s):
# Note, we override with the latest element.
B = NextBitset(B, s[i])
map[B] = i
for each c in alphabet: # O(1) time
B[c,-1] = 0
max_distance = 0
# second pass: O(n)/ O(nlogn) time.
for i from 0 to len(s):
B = NextBitset(B, s[i])
j = map.find(B) # O(1) / O(logn)
max_distance = max(max_distance, j-i)
我不确定阿米特的提议是什么,如果是这样的话,请考虑另一个解释。这可以在一次遍历中完成 为字符串的每个索引生成一个长度等于字母的位集。存储遍历字符串时遇到的每个唯一位集的第一个索引。更新当前和以前看到的位集之间的最大间隔 例如,字符串“aabccab”: 每次迭代的更新可以在O(1)中完成,方法是将每个字符的位掩码预处理为具有上一个位集的
XOR
:
bitset mask
0 1 1
1 XOR 0 = 1
0 0 0
表示更新与字母表位集中第一位相关联的字符。当您说“子字符串”时,您是指连续的子字符串,还是可以省略字符(即子序列)?是的,连续的子字符串(不是子序列)是这样认为的,另一个将非常简单。还是想澄清一下。字母表的大小是恒定的吗?@amit,是的,为了简单起见,我们甚至可以假设只会出现
a-z
字符(实际上我也想到了,可能会有帮助)谢谢你,amit!所以对于“第二次迭代”,我会做一些二进制搜索?(否则需要O(n^2)
)哦,没关系,你提到过一次比较需要O(1)/O(lgn)
,因为它是一个位集。@消除重要的是它是一个大小恒定的位集:)等一下,有点不对:如果你对每个索引都进行第二阶段的比较,你最终会得到O(n^2)
。你是怎么得到线性时间的?(假设比较两个位集的时间为常数)@Elimination在第二阶段,对于每个索引,您只需执行映射查找,即O(1)/O(logn),我将添加一个伪代码来澄清。
a a b c c a b
0 1 2 3 4 5 6 (index)
_
0 1 0 0 0 0 1 1 | (vertical)
0 0 0 1 1 1 1 0 | bitset for
0 0 0 0 1 0 0 0 _| each index
^ ^
|___________|
largest interval
between current and
previously seen bitset
bitset mask
0 1 1
1 XOR 0 = 1
0 0 0