如果您追求子字符串,Trie或 Patrica trie 可能是一个很好的起点。
如果您不关心顺序,只关心每个符号或字母的数量,我会计算所有字符串的直方图,然后将它们与输入的直方图进行比较。
ABCDEFGHIJKLMNOPQRSTUVWXYZ
Hello World => ...11..1...3..2..1....1...
O(26 * m + n)
如果您只考虑不区分大小写的拉丁字母,这将降低一次预处理的成本。
如果 m 是常数,您可以通过对其进行归一化将直方图解释为 26 维单位球体上的 26 维向量。然后你可以计算两个向量的点积,得到两个向量之间夹角的余弦值,这个值应该与字符串的相似度成正比。
假设只有m = 3
一个大小为 3 的字母表A = { 'U', 'V', 'W' }
和以下字符串列表。
L = { "UUU", "UVW", "WUU" }
直方图如下。
H = { (3, 0, 0), (1, 1, 1), (2, 0, 1) }
直方图使用直方图的欧几里得范数h = (x, y, z)
归一化- 即。h' = (x/r, y/r, z/r)
r
h
r = sqrt(x² + y² + z²)
H' = { (1.000, 0.000, 0.000), (0.577, 0.577, 0.577), (0.894, 0.000, 0.447) }
输入S = "VVW"
具有直方图hs = (0, 2, 1)
和归一化直方图hs' = (0.000, 0.894, 0.447)
。
现在我们可以计算两个直方图的相似度,以及两个直方图h1 = (a, b, c)
的h2 = (x, y, z)
欧几里得距离。
d(h1, h2) = sqrt((a - x)² + (b - y)² + (c - z)²)
对于我们得到的例子。
d((3, 0, 0), (0, 2, 1)) = 3.742
d((1, 1, 1), (0, 2, 1)) = 1.414
d((2, 0, 1), (0, 2, 1)) = 2.828
因此“UVW”最接近“VVW”(数字越小表示相似度越高)。
使用归一化直方图h1' = (a', b', c')
,h2' = (x', y', z')
我们可以将距离计算为两个直方图的点积。
d'(h1', h2') = a'x' + b'y' + c'z'
对于我们得到的例子。
d'((1.000, 0.000, 0.000), (0.000, 0.894, 0.447)) = 0.000
d'((0.577, 0.577, 0.577), (0.000, 0.894, 0.447)) = 0.774
d'((0.894, 0.000, 0.447), (0.000, 0.894, 0.447)) = 0.200
再次确定“UVW”最接近“VVW”(数字越大表示相似度越高)。
两个版本产生不同的数字,但结果总是相同的。也可以使用其他范数——例如曼哈顿距离(L1 范数)——但这只会改变数字,因为有限维向量空间中的范数都是等价的。