首先,我想知道 string S
length(m)
和 pattern T
length的边界(n)
。
存在一种一般性的想法,但基于它的解决方案的复杂性取决于模式长度。对于短模式和长模式,复杂性从O(m)
到不等。O(m*n^2)
length<=100
O(n)
算术基本定理指出,每个整数都可以唯一地表示为素数的乘积。
想法 - 我猜,你的字母表是英文字母。所以,字母大小是 26。让我们用第一个素数替换第一个字母,用第二个替换第二个字母,依此类推。我的意思是以下替换:
a->2
b->3
c->5
d->7
e->11 等等。
让我们将某个字符串的字母对应的素数乘积表示为prime product(string)
。例如,primeProduct(z)
将101
是101
第 26 个素数,primeProduct(abc)
将是2*3*5=30
,primeProduct(cba)
也将是5*3*2=30
。
为什么我们选择素数?如果我们替换 a ->2; b -> 3, c-> 4,我们将无法破译示例 4 - 是“c”还是“aa”。
短模式情况的解决方案:对于字符串 S,我们应该计算所有前缀的线性时间素数积。我的意思是我们必须创建数组 A 使得, , . 示例实现:A[0] = primeProduct(S[0])
A[1] = primeProduct(S[0]S[1])
A[N] = primeProduct(S)
A[0] = getPrime(S[0]);
for(int i=1;i<S.length;i++)
A[i]=A[i-1]*getPrime(S[i]);
搜索模式 T。计算 primeProduct(T)。对于'windows'
S 中与模式具有相同长度的所有内容,将其 primeProduct 与 primeProduct(pattern) 进行比较。如果 currentWindow 等于模式或者 currentWindow 是模式 primeProducts 的打乱形式(anagramm),则将是相同的。
重要的提示!我们为 S 的任何子串准备了数组 A 用于快速计算primeProduct 。= = ;primeProduct of(S[i],S[i+1],...S[j])
getPrime(S[i])*...*getPrime(S[j])
A[j]/A[i-1]
复杂性:如果模式长度 <=9,甚至'zzzzzzzzz'
是101^9<=MAX_LONG_INT
; 所有计算都适合标准长类型,复杂度为 O(N)+O(M),其中 N 用于计算模式的 primeProduct,M 遍历 中的所有窗口。S
如果长度<=100,则必须添加 mul/div 长数字的复杂性,这就是复杂性变为O(m*n^2)
. 101^length 的长度是 O(N) mul/div 这样长的数字是O(N^2)
对于长度>=1000 的长模式,最好存储一些哈希映射(素数,度数)。前缀数组将变成哈希映射数组,而A[j]/A[i-1]
技巧将变成 differenceBetween(A[j] 和 A[i-1] 哈希映射的键集)。