I am coming!KMP!

(中二完毕)

 

 

1711:

建议数组用pre命名而不是next,next是c++的关键字

问一个串是否在另一个串中出现过,如出现输出最小出现位置,上模板

--

#include <iostream>
#include <math.h>
#include <string.h>
#include <vector>
#include <map>
#include <queue>
#include <stdio.h>
#include <algorithm>
#include <cstdio>
using namespace std;
int pre[1000009],t[1000009],s[1000009];
int main()
{
    
    
    int T,n,m;
    cin>>T;
    
    while(T--)
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            cin>>t[i];
        }
        
        for(int i=1;i<=m;i++)
        {
            cin>>s[i];
        }
        
        pre[0]=0;
        pre[1]=0;
        
        int k=0;
        for(int i=2;i<=m;i++)
        {
            while(k&&s[i]!=s[k+1]) k=pre[k];
            if(s[i]==s[k+1]) k++;
            pre[i]=k;
        }
        
    
        
        
        int ok=1;
        k=0;
        for(int i=1;ok&&i<=n;i++)
        {
            while(k&&t[i]!=s[k+1]) 
            {
              k=pre[k];    
            }
            
            if(t[i]==s[k+1]) k++;
            
            if(k==m)
            {   ok=0;
                printf("%d\n",i-m+1);
            }
            
        //    cout<<i<<" "<<k<<endl;
        }
        if(ok) cout<<-ok<<endl;
    }
}

 

 

hdu 1686

问s串是否在t串中出现过,求次数,允许重叠。

每次k能匹配到strlen(s)时,num++即可;

#include <iostream>
#include <math.h>
#include <string.h>
#include <vector>
#include <map>
#include <queue>
#include <stdio.h>
#include <algorithm>
#include <cstdio>
using namespace std;
int pre[1000009];
char s[1000009],t[1000009];
int main()
{
    

    
    int T,n,m;
    scanf("%d",&T);
    
    while(T--)
    {
    
          scanf("%s",s+1);
        scanf("%s",t+1);
        
        pre[0]=0;
        pre[1]=0;
        
        int k=0;
        for(int i=2;i<=strlen(s+1);i++)
        {
            while(k&&s[i]!=s[k+1]) k=pre[k];
            if(s[i]==s[k+1]) k++;
            pre[i]=k;
        }

        k=0;
        int num=0;
        
        for(int i=1;i<=strlen(t+1);i++)
        {
            while(k&&t[i]!=s[k+1])   k=pre[k];    
        
            
            if(t[i]==s[k+1]) k++;
            
            if(k==strlen(s+1)) num++;
        //    cout<<i<<" "<<k<<endl;
        }
       printf("%d\n",num);
    }
}

 

--

 

hdu   2087

同上,问出现次数,但不同的是不允许重叠,记录每次出现的位置,最后统计答案时声明一指针,如果ans[i]的起点仍在该指针管辖范围内,就不统计,否则令指针=i,保证不重叠。

虽然说狠狠地暴力一通也能过啦。


#include <iostream> #include <math.h> #include <string.h> #include <vector> #include <map> #include <queue> #include <stdio.h> #include <algorithm> #include <cstdio> using namespace std; int pre[1000009],ans[1000009]; char s[1000009],t[1000009]; int main() { int T,n,m; while(1) { scanf("%s%s",t+1,s+1); if(t[1]=='#') break; pre[0]=0; pre[1]=0; int k=0; for(int i=2;i<=strlen(s+1);i++) { while(k&&s[i]!=s[k+1]) k=pre[k]; if(s[i]==s[k+1]) k++; pre[i]=k; } k=0; int num=0; for(int i=1;i<=strlen(t+1);i++) { while(k&&t[i]!=s[k+1]) k=pre[k]; if(t[i]==s[k+1]) k++; if(k==strlen(s+1)) { num++; ans[num]=i-strlen(s+1)+1; } } if(num==0) { printf("0\n"); continue; } int j=1,cnt=1; for(int i=2;i<=num;i++) { if(ans[i]<=ans[j]+strlen(s+1)-1) continue; cnt++; j=i; } printf("%d\n",cnt); } }