首先,我想知道字符串S长度(m)和模式T长度(n)的边界。
存在一个通用的想法,但基于它的解决方案的复杂性取决于模式长度。复杂性从O(m) 到O(m*n^2) 不等,对于短模式,length<=100 和O(n) 对于长模式。
Fundamental theorem of arithmetic 声明每个整数都可以唯一地表示为素数的乘积。
想法 - 我猜,你的字母表是英文字母。所以,字母大小是 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)。对于 S 中与模式具有相同长度的所有'windows',将其 primeProduct 与 primeProduct(pattern) 进行比较。如果 currentWindow 等于模式或 currentWindow 是模式的乱码形式(anagramm),primeProducts 将是相同的。
重要提示!我们为 S 的任何子串准备了数组 A 用于 快速计算 primeProduct。 primeProduct of(S[i],S[i+1],...S[j]) = getPrime(S[i])*...*getPrime(S[j]) = A[j]/A[i-1];
复杂性:如果模式长度 'zzzzzzzzz' 也是 101^9<=MAX_LONG_INT;所有计算都适合标准长类型,复杂度为 O(N)+O(M),其中 N 用于计算模式的 primeProduct,M 遍历S 中的所有 windows。如果长度O(m*n^2) 的原因。 101^length 的长度是 O(N) mul/div 这样长的数字是O(N^2)
对于长度>=1000 的长模式,最好存储一些哈希映射(素数,度数)。前缀数组将变成哈希映射数组,A[j]/A[i-1] 技巧将变成 differenceBetween(A[j] and A[i-1] hashmaps's key sets)。