每个字符出现偶数次(可能为零)的最长子串

Longest substring where every character appear even number of times (possibly zero)

Suppose we have a string s. We want to find the length of the longest substring of s such that every character in the substring appears even number of times (possible zero).
WC Time: O(nlgn). WC space: O(n)

首先,很明显子串必须是偶数长度。其次,我熟悉滑动 window 方法,在该方法中我们锚定一些 right 索引并寻找最左边的索引来匹配您的标准。我试图在这里应用这个想法,但无法真正表达它。

此外,在我看来优先级队列可以派上用场(因为 O(nlgn) 要求有点暗示)

我很乐意提供帮助!

让我们定义以下位集:

B[c,i] = 1 if character c appeared in s[0,...,i] even number of times.

计算 B[c,i] 需要线性时间(对于所有值):

for all c:
  B[c,-1] = 0
for i from 0 to len(arr):
  B[c, i] = B[s[i], i-1] XOR 1

由于字母表的大小不变,位集也是如此(对于每个 i)。

注意条件:

every character in the substring appears even number of times

对于子字符串 s[i,j] 为真当且仅当索引 i 的位集与索引 j 的位集相同(否则,有一个重复奇数的位该子串中的次数 ; 反方向:如果有一个位重复次数,那么它的位不能相同)。

因此,如果我们将所有位集存储在某个集合中(哈希 set/tree 集合),并且仅保留最新条目,则此预处理需要 O(n)O(nlogn) 时间(取决于 hash/tree设置).

在第二次迭代中,对于每个索引,找到更远的具有相同位集的索引(O(1)/O(logn),取决于是否设置了hash/tree),找到子串长度,并将其标记为候选。最后取最长的候选

此解决方案是 O(n) space 位集,O(n)/O(nlogn) 时间,取决于是否使用 hash/tree 解决方案。


伪代码:

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)

我不确定 amit 到底提出了什么建议,所以如果是这样,请考虑另一种解释。这可以在一次遍历中完成。

为字符串的每个索引生成长度等于字母的位集。存储遍历字符串时遇到的每个唯一位集的第一个索引。更新当前和之前看到的位集之间的最大间隔。

例如字符串,"aabccab":

  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

每次迭代的更新可以在 O(1) 中完成,方法是将每个字符的位掩码预处理为 XOR 和前一个位集:

bitset     mask
  0         1     1
  1   XOR   0  =  1
  0         0     0

表示更新与 alphabet-bitset 中的第一位关联的字符。