day2:字符串问题总结

day2:字符串问题总结

A题:hdu 1711:Number Sequence

一看题,就知道用KMP算法,但是开始用字符串存,发现WA了,于是想到由于数字太大,然后在ASCII码值中没有对应的值,于是就直接采用用整形数组存,然后用KMP算法

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int s1[1000010];
int s2[10010];
int Next[10010];
int main()
{
    int t;
    int n,m;
    int num;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)
        {
            scanf("%d",&s1[i]);
        }
        s1[n]='\0';
        for(int i=0;i<m;i++)
        {
            scanf("%d",&s2[i]);
        }
        s2[m]='\0';
        memset(Next,0,sizeof(Next));
        Next[0]=-1;
        int i=0;
        int j=-1;
        while(i<m)
        {
            if(j==-1||s2[i]==s2[j])
            {
                ++i;
                ++j;
                Next[i]=j;
            }
            else
            {
                j=Next[j];
            }
        }
        i=0,j=0;
        while(i<n&&j<m)
        {
            if(j==-1||s1[i]==s2[j])
            {
                ++i;
                ++j;
            }
            else
                j=Next[j];
        }
        if(j==m)
        {
            printf("%d\n",i-m+1);
        }
        else
            printf("-1\n");
    }
    return 0;
}

B题:hdu 2087:剪花布条

一看也就是用KMP,求子串在模式串中的位置,稍微对KMP算法模板变下行即可;


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
char s1[1010];
char s2[1010];
int Next[1010];
int main()
{
    while(~scanf("%s",s1))
    {
        if(strcmp(s1,"#")==0)
            break;
        scanf("%s",s2);
        int len1=strlen(s1);
        int len2=strlen(s2);
        s1[len1]='\0';
        s2[len2]='\0';
        memset(Next,0,sizeof(Next));
        int i=0;
        int j=-1;
        Next[0]=-1;
        while(i<len2)
        {
            if(j==-1||s2[i]==s2[j])
            {
                ++i;
                ++j;
                Next[i]=j;
            }
            else
                j=Next[j];
        }
        int num=0;
        i=0,j=0;
        while(i<len1&&j<len2)
        {
            if(s1[i]==s2[j]||j==-1)
            {
                ++i;
                ++j;
            }
            else
                j=Next[j];
            if(j==len2)
            {
                j=0;
                num++;
            }
        }
        printf("%d\n",num);
    }
    return 0;
}

看题目发现,如果直接还是单纯用KMP的话,肯定会TLE,这一看就是标准的多模式匹配问题
固然想到AC自动机算法,于是直接套模板即可;

/**单纯用KMP肯定会TLE,于是就想到用AC自动机,发现直接就是套模板即可*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
char str[1000010];
char s[55];
int Tire[1000010][30];      //存字典树
int wordNum[1000010];       //以某结点结束的字符串个数
int fail[1000010];       //失败指针
int cnt=0;
/**建立字典树*/
void build_Tire(char s[])
{
    int root=0;
    int len=strlen(s);
    for(int i=0;i<len;i++)
    {
        int c=s[i]-'a';
        if(!Tire[root][c])
            Tire[root][c]=++cnt;
        root=Tire[root][c];
    }
    wordNum[root]++;            //该位置结束的字符串共有多少个
}
void get_Fail()
{
    queue<int>q;
    /**第二层给失败指针赋值*/
    for(int i=0;i<26;i++)
    {
        if(Tire[0][i])
        {
            fail[Tire[0][i]]=0;
            q.push(Tire[0][i]);
        }
    }
    /**遍历字典树以获得所有失败指针*/
    while(!q.empty())
    {
        int v=q.front();          //当前节点
        q.pop();
        for(int i=0;i<26;i++)
        {
            if(Tire[v][i])
            {
                fail[Tire[v][i]]=Tire[fail[v]][i];
                q.push(Tire[v][i]);
            }
            else
                Tire[v][i]=Tire[fail[v]][i];
        }
    }
}
/**查询*/
int query()
{
    int now=0,ans=0;
    int len=strlen(str);
    for(int i=0;i<len;i++)
    {
        int c=str[i]-'a';
        now=Tire[now][c];
        for(int j=now;j&&wordNum[j]!=-1;j=fail[j])
        {
            ans+=wordNum[j];
            wordNum[j]=-1;
        }
    }
    return ans;
}
int main()
{
    int n,m;
    scanf("%d",&n);
    while(n--)
    {
        memset(Tire,0,sizeof(Tire));
        memset(wordNum,0,sizeof(wordNum));
        scanf("%d",&m);
        for(int i=0;i<m;i++)
        {
            scanf("%s",s);
            build_Tire(s);
        }
        get_Fail();
        scanf("%s",str);
        int ans=query();
        printf("%d\n",ans);
    }
    return 0;
}

D题:hdu 2778:LCR

一道模拟题,但是没做出来,待补。。。。

E题:hdu 1251:统计难题

这题就很无语,难度不是太难,就是求多个模式串的前缀是否等于待匹配串,求出个数,直接就是套字典树模板即可,但是它那个数大小就真的很懵,开小点就Runtime Error,大一点就MLE,然后在杭电交就莫名其妙的过了

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn =2e6+5;
int n,m;
int flag;
int str[maxn][30];
int sum[maxn];
char ss[maxn];
void Insert(char *ss)
{
    int p = 0;
    for(int i = 0; i < strlen(ss); i++)
    {
        int c = ss[i] - 'a';
        if(!str[p][c]) str[p][c] = ++flag;
        sum[str[p][c]]++;
        p = str[p][c];
    }
}
int query(char *k)
{
    int p = 0;
    for(int i = 0; i < strlen(k); i++)
    {
        int c = k[i] - 'a';
        if(!str[p][c]) return 0;
        p = str[p][c];
    }
    return sum[p];
}
int main()
{
    flag = 0;
    while(gets(ss))
    {
        if(ss[0] == '\0') break;
        Insert(ss);
    }
    char k[maxn];
    //printf("111");
    while(~scanf("%s",k))
    {
        printf("%d\n",query(k));
    }

    return 0;
}

F题:hdu 2072:单词数

同样也是一道字典树的题,但是用set会更加简单,而今天又是学字符串,但是我还是用set写的,hhh

/**i dislike submit failed*/
#include<bits/stdc++.h>
using namespace std;
int main()
{
    string str,word;
    set<string>SET;
    int n;
    while(getline(cin,str))
    {
        SET.clear();
        n=0;
        if(str!="#")
        {
            stringstream ss(str);
            while(ss>>word)
            {
                n++;
                SET.insert(word);
            }
            cout<<SET.size()<<endl;
        }
        else
            break;
    }
    return 0;
}

G题:hdu 2243

待补。。。

H题:hdu 1671:Phone List

同样也是一道字典树模板题,敲完即可

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=100010;
int Tire[maxn][26];
int wordNum[maxn];
char str[100010][20];
int cnt=0;
void build_Tire(char str[])
{
    int len=strlen(str);
    int root=0;
    for(int i=0;i<len;i++)
    {
        int c=str[i]-'0';
        if(!Tire[root][c])
            Tire[root][c]=++cnt;
        root=Tire[root][c];
        /**重点在这里*/
        wordNum[root]++;
    }
}
int Find(char str[])
{
    int root=0;
    int len=strlen(str);
    for(int i=0;i<len;i++)
    {
        int c=str[i]-'0';
        if(Tire[root][c]==0)
            return 0;
        root=Tire[root][c];
    }
    return wordNum[root];
}
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        memset(Tire,0,sizeof(Tire));
        memset(wordNum,0,sizeof(wordNum));
        cnt=0;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%s",str[i]);
            build_Tire(str[i]);
        }
        int flag=0;
        for(int i=0;i<n;i++)
        {
            if(Find(str[i])>1)
            {
                flag=1;
                break;
            }
        }
        if(flag==0)
            printf("YES\n");
        else
            printf("NO\n");
    }
}

今天还是偷懒了,后缀数组都没看下,然后另外一套居然一道题都没做。。。

加油加油,明天选拔赛但愿能多做出来几道

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值