String Problem HDU - 3374 (最大最小表示法+kmp求模式次数)

题目链接

题目大意:给你一个字符串,求它所有同构串(末尾元素移1个到开头算一次同构)中,字典序最大以及最小的串出现的位置。
位置由题目定义:如给出 SKYLONG
SKYLONG 1
KYLONGS 2
YLONGSK 3
LONGSKY 4
ONGSKYL 5
NGSKYLO 6
GSKYLON 7

很显然是一道最大最小表示法模板题。
思路就是先预处理字符串str,使得str=str+str;然后求出最大最小字符串起始点,分别用kmp算法求出其在str(预处理之后的)中的出现次数就好了(此时的str要去掉末尾字符,否则第一个字符串会出现两次 ,比如str=abcd,str=str+str,得str==abcdabcd,匹配时要变成abcdabc)。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define INF 1000000
#define MAX 2000005
//最小表示法:设置2个指针p1=0,p2=1,代表可能的开头位置,向后探寻,如果相等就k++,否则如果p2更大,这个指针就
//暂时不得作为开头位置,更新到p1后面位置,也就是max(p2+k+1,p1+1)
int minpress(string s,int n)
{
    int p1=0,p2=1,k=0;//p1 p2都有可能是开头,先假设p1是开头
    while(p1<n && p2<n)
    {
        k=0;
        while(k<n && s[p1+k]==s[p2+k]) k++;//一路相等
        if(k==n) break;
        if(s[p1+k]>s[p2+k]) p1=max(p2+1,p1+k+1);//发现p1开头的会大于p2开头的,所以把p2变成开头,p1到p2后面去
        else if(s[p1+k]<s[p2+k]) p2=max(p1+1,p2+k+1);//p1保留作为开头,p2到达p2+k的下一位,看看p2+k+1会不会小于p1号元素
    }
    return min(p1,p2);
}
int maxpress(string s,int n)
{
    int p1=0,p2=1,k=0;
    while(p1<n && p2<n)
    {
        k=0;
        while(k<n && s[p1+k]==s[p2+k]) k++;//一路相等
        if(k==n) break;
        if(s[p1+k]<s[p2+k]) p1=max(p2+1,p1+k+1);//p1开头目前行不通
        else if(s[p1+k]>s[p2+k]) p2=max(p1+1,p2+k+1);
    }
    return min(p1,p2);
}
int kmp(string pattern,string s)//返回出现次数
{
    int ans=0;
    int len1=s.size(),len2=pattern.size();
    s[len1-1]='\0';//最后一个字符加了的话,第一个会出现两次
    int match[len2+2];
    match[0]=-1;
    for(int i=1;i<len2;i++)
    {
        int j=match[i-1];
        while(j>=0 && pattern[j+1]!=pattern[i]) j=match[j];
        if(pattern[j+1]==pattern[i]) match[i]=j+1;
        else match[i]=-1;
    }
    int p1=0,p2=0;
    while(p1<len1)
    {
        if(pattern[p2]==s[p1]) p1++,p2++;
        else if(p2>0) p2=match[p2-1]+1;
        else p1++;
        if(p2==len2)
        {
            p2=match[p2-1]+1;//kmp求匹配次数的通用模板
            ans++;
        }
    }
    return ans;
}
int main() 
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    string s;
    while(cin>>s)
    {
        int len=s.size();
        s+=s;
        int minp=minpress(s,len)+1;
        int maxp=maxpress(s,len)+1;
        string s1=s.substr(minp-1,len),s2=s.substr(maxp-1,len);
        int times_minp=kmp(s1,s);
        int times_maxp=kmp(s2,s);
        printf("%d %d %d %d\n",minp,times_minp,maxp,times_maxp);
    }
    system("pause");
    return 0;
}

```时间290ms左右

你可能感兴趣的:(字符串)