【问题标题】:Linear space data-structure supporing subsequence query on a static string支持静态字符串子序列查询的线性空间数据结构
【发布时间】:2018-07-19 15:35:32
【问题描述】:

从长度为 n 的给定字符串 S 构建数据结构,支持快速查询以检查输入字符串是否长度为 J mS 的子序列。

S是静态字符串,数据结构的预处理时间可以忽略。


要求:

  • 空间消耗应该是线性的O(n)
  • subsequence(J) 的运行时间应该取决于 m - 不一定是 O(m),但越快越好。

什么是子序列?

AB 的子序列,如果 A 可以通过从 B 中删除零个或多个字符来构造.即ABAADBDBAC 的子序列

我尝试了什么

支持Subsequence(J) 查询的数据结构存储从S 中的每个字母到字母表中每个字母在S 中下一个出现的指针。 p>

A 为长度为 n + 1 的数组。 A 包含散列在字母表 σ 上的哈希表。哈希表中的每个键值对 (k,v) 都包含一些字母 k 作为键,它的下一次出现作为值 v

  • 哈希表 A_0 包含字母表中每个字母的第一次出现。

  • 哈希表 A_1 包含字母在 S_0 的第二次出现的索引以及其他字母的第一次出现。

  • 哈希表 A_2 包含字母 S_1S_2 的第二次出现的索引,假设它们是不同的字母 -否则 A_2 将在 S_1 处包含字母的第三个索引 - 以及其他字母的第一次出现,依此类推...

例子:如果TB C A D F B¥代表散列表A_0,代表一个Ø null指针,数据结构看起来像: |0 1 2 3 4 5 |¥ B C A D B A|3 3 3 Ø Ø Ø B|1 5 5 5 5 Ø C|2 2 Ø Ø Ø Ø D|4 4 4 4 Ø Ø

字母表 \sigma 是由 T 中的字母构成的,并且是静态的。因此,可以使用完美哈希(FKS)。

运行查询

要使用字符串 J 执行 Subsequence(J) 查询,我们在 中查找第一次出现 J_0A-index >S 使用 A_0

在示例中,我们可以查询Subsequence("BAB") 来测试BAB 是否是子序列: * 在返回索引 1 的列 0 中查找 B * 在返回索引 3 的第 1 列中查找 A * 在返回索引 5 的第 3 列中查找 B

只要我们不传递空指针,字符串就是子序列。哈希查找需要固定时间,我们最多只能执行 |J| 个,运行时间为 O(|J|)

空间消耗为O(|J|·|S|)

【问题讨论】:

  • 你尝试了什么?
  • 字母的大小是不变的吗?
  • @wp78de 我的第一次发帖很糟糕 - 我查看了文档并添加了我尝试过的部分。
  • @pkpnd 是的,字符串 S 是在我们构建数据结构之前给出的。
  • @DannyDannyDanny 这不是我问的。有多少种不同的字母?不管 S 有多长,S 是否可以包含所有不同的字符?

标签: string algorithm data-structures subsequence


【解决方案1】:

检查 J 是否是 S 的子序列的简单而缓慢的方法是:

  1. S的开头开始
  2. 对于 J 中的每个字符 c,按顺序在 S 中前进到下一个出现的 c.
  3. 如果你坚持到最后并为每个字符找到匹配项,那么 J 就是 S 的子序列。

您可以通过构建从 S 中出现的每个字符到该字符出现位置的排序数组的映射来加速这些搜索。

然后,要在步骤 (2) 中查找字符的下一个匹配项,您可以查找该字符的位置数组,并在数组中进行二分查找,以查找当前位置之后的下一个匹配项。

进行子序列检查的总最坏情况复杂度将是 O(m log n)

【讨论】:

  • 谢谢,您的想法帮了我很大的忙,并为我指明了正确的方向。我发现了一种改进的方法,它映射到 Y-fast-tries 而不是排序数组。这给出了 O(m log log n) 的时间复杂度。
  • @pkpnd 不是这样 - 你不需要为字符使用数组 -> 位置映射,并且你不需要为不出现的字符存储位置。
猜你喜欢
  • 2013-08-02
  • 2015-07-12
  • 2012-05-03
  • 1970-01-01
  • 2023-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-21
相关资源
最近更新 更多