HDU-1711 Number Sequence(KMP裸题)

题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1711

题目描述

给定两个数字序列 a[] 和 b[],b[] 有可能整体作为一个连续子序列出现在了 a[] 中,现在请你找出 b[] 在 a[] 中第一次出现的位置(起始位置从 1 开始计数),如果一次都没有出现,请输出 -1。

输入格式

第一行包含一个数字 T,表示测试用例的个数。
对于每组测试用例,第一行包含两个数字 n m ( 1<= n <= 1000000, 1 <= m <= 10000 ),表示 a[] 和 b[] 的长度。
接下来的一行包括 n 个数字,依次表示 a[1], a[2], a[3] … a[n],-1000000 <= a[i] <= 1000000
接下来的一行包括 m 个数字,依次表示 b[1], b[2], b[3] … b[m],-1000000 <= b[i] <= 1000000

输出格式

对于每组数据输出一行,请输出 b[] 整体作为一个连续子序列在 a[] 中的首次出现位置的起始下标,如果一次都没有完整出现,输出 -1。

做题过程
想着这不就是传说中的KMP裸题吗。。。然后就直接提交,结果直接编译错误,我就开始找错,一点一点的调试,然后发现main()里面的一百万的数组有问题,然后就上网搜资料,最后找到答案,开大数组最好在函数外开!,因为main函数里面占用的是栈空间,这个空间一般比较小,只有几十kb,如果在这里开大数组,会造成栈溢出,所以要定义全局的数组,数据段的空间很大。点此查看原因
然后我改过之后提交,结果时间超限了,很难受,心想难道又是我的代码问题吗,最后找到了,根源在C++的cin流问题,这个问题我之前遇到过,C++提速小技巧
然后直接贴上 ios::sync_with_stdio(false); 就可以了。

PS:重复出现的烦人代码可以用宏定义来简化
原代码:

memset(s,0,sizeof(s));
memset(t,0,sizeof(t));
memset(next,0,sizeof(next));

改进之后代码

#define ms(x,n) memset(x,n,sizeof(x));
...
...
ms(s,0);ms(t,0);ms(net,0);

代码

#include <iostream>
#include <cstring>
#define ms(x,n) memset(x,n,sizeof(x));
using namespace std;
const int nmax=1000011;
const int mmax=10011;

int n,m;
int s[nmax],t[mmax],net[mmax];

void GetNext()
{
    //求出模式串t的net数组值
    int j,k;//j扫描t,k记录t[j]之前与t开头相同的字符个数
    j=0,k=-1;
    net[0]=-1;
    while(j<m-1)
    {
        if(k==-1||t[j]==t[k])
        {
            j++,k++;//j,k依次移动到下一个字符
            net[j]=k;//设置next的值
        }
        else
            k=net[k];//k回溯
    }
}
int KMP()
{
    GetNext();
    int i=0,j=0;
    while( j<m&&i<n)
    {
        if(j==-1||s[i]==t[j])
        {
            i++,j++;
        }
        else
            j=net[j];

    }
    if(j==m)
        return (i-m+1);
    else
        return -1;
}
int main()
{
    ios::sync_with_stdio(false);
    int x;
    cin>>x;
    while(x--)
    {
        ms(s,0);ms(t,0);ms(net,0);
        cin>>n>>m;
        for(int i=0;i<n;i++)
            cin>>s[i];
        for(int i=0;i<m;i++)
            cin>>t[i];
        cout<<KMP()<<endl;
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值