Algorithm 搜索与模式匹配的字符串";abc:*:xyz";在小于O(n)的范围内

Algorithm 搜索与模式匹配的字符串";abc:*:xyz";在小于O(n)的范围内,algorithm,string,data-structures,Algorithm,String,Data Structures,给定一组字符串,我需要找到匹配3种模式的字符串: 前缀搜索-abc* 类球形图案-abc::::xyz 后缀搜索-*xyz 其中*是一个通配符(可以匹配任意数量的字符) 现在直接的解决方案就是扫描每个字符串,看看它是否与目标模式匹配。但这是O(n)。如果我将字符串存储在平衡搜索树中,我可以在O(logn)中执行前缀查询。如果我再创建一棵树,所有字符串基本上都颠倒了,那么我可以在O(logn)中进行后缀查询。有没有一种聪明的方法可以有效地搜索“abc::::xyz”模式?其他两个查询结果的交集

给定一组字符串,我需要找到匹配3种模式的字符串:

  • 前缀搜索-abc*
  • 类球形图案-abc::::xyz
  • 后缀搜索-*xyz
其中*是一个通配符(可以匹配任意数量的字符)


现在直接的解决方案就是扫描每个字符串,看看它是否与目标模式匹配。但这是O(n)。如果我将字符串存储在平衡搜索树中,我可以在O(logn)中执行前缀查询。如果我再创建一棵树,所有字符串基本上都颠倒了,那么我可以在O(logn)中进行后缀查询。有没有一种聪明的方法可以有效地搜索“abc::::xyz”模式?

其他两个查询结果的交集不正是这样吗?既然每个结果都是O(logn),并且结果集大小中该结果集的相交点是O(N),那么总数不也是原始问题的O(logn)吗?

如果您考虑将字符串存储在搜索树中的可能性,为什么不同时存储属性“以abc开头”和“以xyz结尾”,将这些属性用作键

编辑: 您还可能希望将Big-O标记法抛在脑后,而将注意力集中在特定用例中实际预期的搜索持续时间上。这可能是一个更现实的方法;当涉及到实际搜索效率时,算法/实现的O(f(n))样式的等级可能不会为您提供太多有用的信息。

如果“abc”和“xyz”是固定值,您可以在集合中维护三个计数器,指示字符串的数量:

  • 以“abc”开头,但不以“xyz”结尾
  • 不是以“abc”开头,而是以“xyz”结尾
  • 以“abc”开头,以“xyz”结尾
这为搜索提供了O(1)时间复杂度,但在插入集合或从集合中删除时,需要额外计算

如果“abc”和“xyz”是任意字符串,则所有操作都是O(n),包括“abc…”一个。您只需考虑当集合包含所有从“ABC”开始的项目时会发生什么。这根本不受O(logN)的限制,因为您必须处理树中的所有项(每个非叶节点的两个分支)

我认为理想的解决方案是保持两个有序树,一个用于普通字符串,另一个用于反向字符串。但是不要担心尝试在两者之间进行交叉。您所需要做的就是尽可能减少搜索空间

  • 要查找“abc…”,请使用普通树查找以该值开头的字符串
  • 要查找“…xyz”,请使用反向树查找以该值(zyx…)的反向结尾的字符串
  • 要查找“abc…xyz”,请使用普通树查找以该值开头的字符串,然后过滤掉那些不以“xyz”结尾的字符串

这样,您就不必担心两棵树之间的交叉值,而且与简单的线性搜索相比,您仍然可以获得性能改进。

生成每个单词的旋转,并将每个旋转放在后缀树中,并指示“旋转索引”

例如,要放置字符串“hello”,请将

还有,你把“英雄”当作

还有,你把“ohe”(不要问我ohe是什么)

然后,如果需要搜索模式 “he*o”,您需要旋转它,直到得到前缀字符串: “ohe*”

在后缀树中,您可以找到候选项:(ohell,4),(oher,3),(ohe,0)。
然后恢复它们的原始版本(通过取消旋转它们),并选择正确的版本-“你好”和“英雄”。

相交为O(N)是基于这样的假设,即从原始树中检索到的两个结果集也已排序;)在最坏的情况下仍然是O(N)。不,这仍然是O(N)由于结果集大小仍然是有界的,因此可以更正确地说,组合运算的顺序与“前缀”和“后缀”运算的顺序相同。我从O(log N)的语句中假设在他的问题中,典型的结果集中只有对数N个元素的顺序,否则他也不能在这段时间内进行前缀或后缀操作。如果你对第一种和最后一种情况有一个解决方案,那么你就对中间情况有一个解决方案。为什么中间字符是什么很重要?只应用第一种解决方案ion,然后是最后一个,如果它们都起作用,那么你就匹配了中间的情况。它也是O(1)(如果你使用的是“pascal字符串”-除了C类以外的所有东西都是这样做的)@Pod,对于给定的字符串可能是O(1),但N是字符串的数量,因此O(N)。“abc”和“xyz”当然是任意的。好吧,你说得对,它不是O(logn)。我应该避免在Big-O中提及任何内容。但在大多数情况下,您肯定可以删除树的某些分支。这很聪明!它重写了其他两种类型的查询(glob和suffix)进入前缀查询。但不幸的是,它不节省空间-实际上,为每个字符串生成和存储所有旋转比线性扫描更糟糕。是的,你是对的。我不应该提到big-O。我只关心平均情况效率,而不是最坏情况。
hello, 0
elloh, 1
llohe, 2
lohel, 3
ohell, 4
hero, 0
eroh, 1
rohe, 2
oher, 3
ohe, 0
heo, 1
eoh, 2