【发布时间】:2016-09-08 13:57:58
【问题描述】:
长问题描述
模糊字符串匹配器实用程序,如fzf 或CtrlP 过滤具有给定搜索字符串作为子序列的字符串列表。 例如,假设用户想要在文件列表中搜索特定照片。查找文件
/home/user/photos/2016/pyongyang_photo1.png
输入ph2016png 就足够了,因为这个搜索字符串是这个文件名的一个子序列。 (注意这不是 LCS。整个搜索字符串必须是文件名的子序列。)
检查给定的搜索字符串是否是另一个字符串的子序列很简单,但我想知道如何有效地获得最佳匹配:在上面的示例中,有多个可能的匹配。一个是
/home/user/<b>ph</b>otos/<b>2016</b>/<b>p</b>yo<b>n</b>gyan<b>g</b>_photo1.png
但用户可能想到的是
/home/user/photos/2016/pyongyang_photo1.png
为了形式化这一点,我将“最佳”匹配定义为由最少数量的子字符串组成的匹配。第一个示例匹配的数字为 5,第二个示例匹配的数字为 3。
我想出这个是因为获得最佳匹配来为每个结果分配分数以进行排序会很有趣。不过我对近似解不感兴趣,我对这个问题的兴趣主要是学术性质的。
tl;dr 问题描述
给定字符串s 和t,在t 的子序列中找到一个等于s 的子序列,该子序列使t 中的连续元素对的数量最大化。
到目前为止我已经尝试过什么
为了讨论,让我们调用搜索查询s 和测试字符串t。问题的解决方案用fuzzy(s, t) 表示。我将使用 Python 的字符串切片表示法。最简单的方法如下:
由于任何解决方案都必须按顺序使用来自s 的所有字符,因此解决此问题的算法可以从在t(索引i)中搜索s[0] 的第一次出现开始,然后使用更好的两种解决方案中的一种
t[:i+1] + fuzzy(s[1:], t[i+1:]) # Use the character
t[:i] + fuzzy(s, t[i+1:]) # Skip it and use the next occurence
# of s[0] in t instead
这显然不是解决这个问题的最佳方案。相反,这是显而易见的蛮力。 (我曾尝试同时搜索最后一次出现的 s[-1] 并在此问题的早期版本中使用此信息,但结果证明这种方法不起作用。)
→ 我的问题是:解决这个问题最有效的方法是什么?
【问题讨论】:
-
不错的一个!!!一些澄清:(1)你说最好的匹配是具有最少数量的部分。这是否意味着输入必须的所有字符都可以找到并且顺序正确? (2) 如果在同一个字符串中有多个可能的匹配项,并且都带有相同数量的零件?部件之间的距离是否有趣?
-
输入的所有字符必须以正确的顺序找到。如果有几个可能的匹配最大化约束,那么返回其中一个就足够了。
-
第二部分表示仅找到第一个匹配项是不够的,但必须扫描整个字符串以确认没有(更好的)匹配项,对吧?
-
是的,除非有办法证明不可能有更好的匹配。例如,如果我在上面概述的情况下搜索
photo,那么整个查询作为单个子字符串包含在文件名中 - 显然没有比这更好的匹配了。 -
对于长度为 n 和 m 的 2 个字符串,这可以使用 Gotoh 的算法在 O(nm) 时间和空间内精确解决,该算法将 2 个字符串与间隙打开成本对齐。您需要做的就是指定一个非零的间隙打开成本,并禁止删除(或等效地,为删除分配巨额罚款)。
标签: algorithm dynamic-programming string-matching fuzzy-search