Chiryen

导航

HDOJ(1238) KMP

Substrings

http://acm.hdu.edu.cn/showproblem.php?pid=1238

先找到长度最短的字符串,把它的子串和该子串的逆序(按长度从大到小)依次与其他字符串匹配。

如果某个子串或它的逆序(如:“ro” ,”or“)和其他字符串都匹配,就返回此时的长度。

#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;

//下标以0开始的KMP
void get_next(string b, int *next)
{
    int i=0;
    int j=-1;
    next[i]=-1;
    int len_b=b.size();
    while(i<len_b-1)
    {
        if(j==-1||b[i]==b[j])
        {
            ++i;
            ++j;
            if(b[i]!=b[j])
                next[i]=j;
            else
                next[i]=next[j];
        }
        else
        {
            j = next[j];
        }
    }
}

int KMP(string a,string b)
{
    int i=0;
    int j=0;
    int len_a=a.size();
    int len_b=b.size();
    int next[101];
    get_next(b,next);
    while(i<len_a&&j<len_b)
    {
        if(j==-1||a[i]==b[j])
        {
            ++i;
            ++j;
        }
        else
        {
            j=next[j];
        }
    }
    if(j>=len_b)
        return 1;
    else
        return 0;
}

int solve(vector<string> str,int mini)
{
    string sub1,sub2;
    int i,j,k,m,res=0;
    int len=str[mini].size();
    for(i=len;i>=1;i--)
    {
        for(j=0;i+j<=len;j++)
        {
            sub1=str[mini].substr(j,i);  //选取str[mini]中以j开头长度为i的字串
            sub2=sub1;
            reverse(sub2.begin(),sub2.end());//逆置字符串
            int l=str.size();
            for(k=0;k<l;k++)
            {
                string s=str[k];
                if(KMP(s,sub1)==0&&KMP(s,sub2)==0)
                {
                    break;
                }
            }
            if(k>=l)
            {
                
                res=i;
                goto A;
            }
        }
    }
    A: return res;
}
int main()
{
    int t,n,i,mini;
    vector<string> str;
    string s;
    scanf("%d",&t);
    while(t--)
    {
        str.clear();
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
            cin>>s;
            str.push_back(s);
        }
        mini=0;
        int len=str.size();
        for(i=1;i<len;i++)
        {
            if(str[i].size()<str[mini].size())
            {
                mini=i;
            }
        }
        printf("%d\n",solve(str,mini));
    }
    return 0;
}
View Code

 

KMP模板

下标以0开始

void get_next(string b, int *next)
{
    int i=0;
    int j=-1;
    next[i]=-1;
    int len_b=b.size();
    while(i<len_b-1)
    {
        if(j==-1||b[i]==b[j])
        {
            ++i;
            ++j;
            if(b[i]!=b[j])
                next[i]=j;
            else
                next[i]=next[j];
        }
        else
        {
            j = next[j];
        }
    }
}

int KMP(string a,string b)
{
    int i=0;
    int j=0;
    int len_a=a.size();
    int len_b=b.size();
    int next[101];
    get_next(b,next);
    while(i<len_a&&j<len_b)
    {
        if(j==-1||a[i]==b[j])
        {
            ++i;
            ++j;
        }
        else
        {
            j=next[j];
        }
    }
    if(j>=len_b)
        return i-len_b;
    else
        return 0;
}
View Code

下标从1开始

void get_next(char *b,int *next)
{
    int i=1;
    int j=0; 
    next[1]= 0; 
    int len_b=strlen(b)-1;     //下标从1开始,子串的长度=strlen(b)-1
    while(i<len_b) 
    { 
        if(j==0||b[i]==b[j])   //b[i]表示后缀的单个字符
        {                      //b[j]表示前缀的单个字符
            ++i; 
            ++j; 
            if (b[i]!=b[j]) 
                next[i]=j; 
            else 
                next[i]=next[j]; 
        }  
        else   
            j=next[j];        //若字符不相同,则j值回溯
    } 
}
int KMP(char *a,char *b,int pos)
{
    int i=pos;               //i用于主串a当前位置下标值
                             //若pos不为1,则从pos开始
    int j=1;                 //j用于字串b当前位置下标值
    int len_a=strlen(a)-1; 
    int len_b=strlen(b)-1;
    int next[101];
     get_next(b,next);        //对字串b分析,得到next数组
    while(i<=len_a&&j<=len_b)
    {
        if(j==0||a[i]==b[j])
        {
            ++i;
            ++j;
        }
        else
        {
            j=next[j];
        }
    }
    if(j>len_b)
        return i-len_b;   
    else
        return 0;
}
View Code

 

下标以1开始的next数组,实际上,是下标以0开始的next数组的值+1。KMP算法最重要的是得到子串的next[]。

posted on 2013-08-20 10:46  Chiryen  阅读(371)  评论(0编辑  收藏  举报