给定两个字符串S和T,其中T是模式字符串。查找字符串S中是否存在任何加扰形式的模式字符串作为SubString,如果存在则返回起始索引。
示例:
字符串S:abcdef 字符串T:efd
字符串S有“def”,搜索字符串T的组合:“efd”。
我找到了一个运行时间为O(m * n)的解决方案。我正在研究一个线性时间解决方案,我习惯使用HashMaps(静态一个,为String T维护,另一个是前一个HashMap的动态副本,用于检查T的当前子串)。我开始检查它失败的下一个字符。但在最坏的情况下,这在O(m * n)中运行。 我想得到一些指示,让它在O(m + n)时间内工作。任何帮助将不胜感激。
答案 0 :(得分:2)
首先,我想知道字符串S
长度(m)
和模式T
长度(n)
的边界。
存在一个总体思路,但基于它的解决方案的复杂性取决于模式长度。对于包含O(m)
和O(m*n^2)
的短模式,复杂度从length<=100
到O(n)
不等。
Fundamental theorem of arithmetic表示每个整数都可以唯一地表示为素数的乘积。
想法 - 我想,你的字母是英文字母。所以,字母大小为26.让我们用第一个素数替换第一个字母,用第二个字母替换第二个字母,依此类推。我的意思是以下替换:a->&gt; 2
b-&gt; 3
c-> 5
d-&gt; 7
e-&gt; 11等等。
让我们将与某些字符串的字母对应的素数的乘积表示为prime product(string)
。例如,primeProduct(z)
为101
,101
为第26个素数,primeProduct(abc)
为2*3*5=30
,primeProduct(cba)
也为{ {1}}。
为什么我们选择素数?如果我们替换 - > 2; b - &gt; 3,c-&gt; 4,我们将无法解读exapmle 4 - 是“c”还是“aa”。
短模式案例的解决方案:
对于字符串S,我们应该计算所有前缀的线性时间素数产品。我的意思是我们必须创建数组A,5*3*2=30
,A[0] = primeProduct(S[0])
,A[1] = primeProduct(S[0]S[1])
。示例实施:
A[N] = primeProduct(S)
搜索模式T.计算primeProduct(T)。对于S中与模式具有相同长度的所有A[0] = getPrime(S[0]);
for(int i=1;i<S.length;i++)
A[i]=A[i-1]*getPrime(S[i]);
,将它的primeProduct与primeProduct(模式)进行比较。如果currentWindow等于模式或currentWindow是一个scrumbled形式(anagramm)的模式primeProducts将是相同的。
重要提示!我们为 S 的任何子字符串的快速计算 primeProduct准备了数组A. 'windows'
= primeProduct of(S[i],S[i+1],...S[j])
= getPrime(S[i])*...*getPrime(S[j])
;
复杂性:如果模式长度<= 9,则偶数A[j]/A[i-1]
为'zzzzzzzzz'
;所有计算都符合标准长类型,复杂度为O(N)+ O(M),其中N用于计算模式的primeProduct,M在101^9<=MAX_LONG_INT
中的所有窗口上进行迭代。如果长度<= 100,则必须增加mul / div长数的复杂度,这就是复杂度变为S
的原因。长度为101 ^长度为O(N)mul / div这样的长数是O(m*n^2)
对于长度> = 1000的长模式,最好存储一些哈希映射(素数,度)。前缀数组将成为哈希映射数组,O(N^2)
技巧将变为(A [j]和A [i-1]个哈希映射的键集)之间的差异。
答案 1 :(得分:0)
如果字母表不是太大(比如ASCII),那么就不需要使用哈希来处理字符串了。
只需使用与字母表大小相同的大数组,并且存在检查变为O(1)
。因此整个算法变为O(m+n)
。
答案 2 :(得分:0)
这个JavaScript示例是线性时间吗?
<script>
function matchT(t,s){
var tMap = [], answer = []
//map the character count in t
for (var i=0; i<t.length; i++){
var chr = t.charCodeAt(i)
if (tMap[chr]) tMap[chr]++
else tMap[chr] = 1
}
//traverse string
for (var i=0; i<s.length; i++){
if (tMap[s.charCodeAt(i)]){
var start = i, j = i + 1, tmp = []
tmp[s.charCodeAt(i)] = 1
while (tMap[s.charCodeAt(j)]){
var chr = s.charCodeAt(j++)
if (tmp[chr]){
if (tMap[chr] > tmp[chr]) tmp[chr]++
else break
}
else tmp[chr] = 1
}
if (areEqual (tmp,tMap)){
answer.push(start)
i = j - 1
}
}
}
return answer
}
//function to compare arrays
function areEqual(arr1,arr2){
if (arr1.length != arr2.length) return false
for (var i in arr1)
if (arr1[i] != arr2[i]) return false
return true
}
</script>
输出:
console.log(matchT("edf","ghjfedabcddef"))
[3, 10]
答案 3 :(得分:0)
让我们考虑一下给定的例子, 字符串S:abcdef 字符串T:efd
创建一个HashSet,它由子串T中的字符组成。因此,该集合包含。
为子串T生成标签: 1e1f1d 。 (每个字符的出现次数+字符本身,可以使用类似于计数排序的技术完成)
现在我们必须为子字符串长度的输入生成标签。
让我们从第一个位置开始,它具有角色a。由于它不存在,我们不创建任何子字符串并移动到下一个字符b。同样,对于角色c然后在d停止。
由于d存在于HashSet中,因此每次出现该字符时都会生成标签(子字符串长度)。我们可以在不同的函数中执行此操作以避免清除计数数组(这样做会降低从O(m * n)到O(m + n)的复杂性)。如果在任何时候输入字符串不包含子字符串T,我们可以从下一个位置开始生成标签(因为发生中断的位置不能是字谜的一部分)。
因此,通过生成标签,我们可以解决线性O(m + n)时间复杂度的问题。
m:输入字符串的长度, n:子串的长度。
答案 4 :(得分:0)
下面的代码我用于 GFG 中的模式搜索问题,它在所有测试用例中都被接受并且在线性时间内工作。
// { Driver Code Starts
import java.util.*;
class Implement_strstr
{
public static void main(String args[])
{
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
sc.nextLine();
while(t>0)
{
String line = sc.nextLine();
String a = line.split(" ")[0];
String b = line.split(" ")[1];
GfG g = new GfG();
System.out.println(g.strstr(a,b));
t--;
}
}
}// } Driver Code Ends
class GfG
{
//Function to locate the occurrence of the string x in the string s.
int strstr(String a, String d)
{
if(a.equals("") && d.equals("")) return 0;
if(a.length()==1 && d.length()==1 && a.equals(d)) return 0;
if(d.length()==1 && a.charAt(a.length()-1)==d.charAt(0)) return a.length()-1;
int t=0;
int pl=-1;
boolean b=false;
int fl=-1;
for(int i=0;i<a.length();i++)
{
if(pl!=-1)
{
if(i==pl+1 && a.charAt(i)==d.charAt(t))
{
t++;
pl++;
if(t==d.length())
{
b=true;
break;
}
}
else
{
fl=-1;
pl=-1;
t=0;
}
}
else
{
if(a.charAt(i)==d.charAt(t))
{
fl=i;
pl=i;
t=1;
}
}
}
return b?fl:-1;
}
}
这是问题https://practice.geeksforgeeks.org/problems/implement-strstr/1
的链接