HDU 1686 统计子串的个数 kmp 调了半天

5 篇文章 0 订阅

题意不解释了。

第一版本代码:WA

#include <iostream>
#include <cstring>
using namespace std;
char s1[1000000+10], s2[10000+10];

void get_nextval(char* T, int nextval[])
{
    int i = 1, j = 0;
    nextval[1] = 0;
    while(i < T[0])
        if(j == 0 || T[i] == T[j]) {
            ++i;
            ++j;
            if(T[i] != T[j]) 
                nextval[i] = j;
            else
                nextval[i] = nextval[j];
        } else 
            j = nextval[j];
}

int Index_KMP(char* S, char* T, int pos, int next[])
{
    int i = pos, j = 1;
    while(i <= S[0] && j <= T[0])
        if(j == 0 || S[i] == T[j]) {
            ++i;
            ++j;
        } else
            j = next[j];
    if(j > T[0])
        return i - T[0];
    else
        return 0;
}

int main()
{
    int t;
    cin >> t;
    getchar();
    while(t--) {
        int n, m, i;
        memset(s1, 0, sizeof(s1));
        memset(s2, 0, sizeof(s2));
        gets(s2+1);
        gets(s1+1);
        n = strlen(s1+1);
        m = strlen(s2+1);
        s1[0] = n;
        s2[0] = m;
        
        int *next = new int[m+1];

        get_nextval(s2, next);
        int pos = 1;
        int cnt = 0;
        while(pos <= n - m +1) {
            if((pos =Index_KMP(s1, s2, pos, next)) != 0) {
                cnt++;
                pos = pos + 1;
            }
            else 
                break;
        }

        cout << cnt << endl;
        delete[] next;
    }
    return 0;
}

没发现哪里明显的错误。网上参考了一下代码。模仿在kmp里面进行统计。在最后一个匹配的时候进行下标转化

这个由于下标的不同会导致,next[len2+1]无定义。程序出错。代码优化后也会使得减少了匹配数目。

一个解决方法是,不使用改进后的kmp算法。而采用原始kmp算法计算next数组。

虽然在本机上测试通过,这时候的代码还是wa。怀疑数据的问题。后来调试的时候发现S[0],T[0]是char的类型。而char的存储范围明显不足。改用int存储后,顺利AC

AC代码:

#include <iostream>
#include <cstring>
using namespace std;
char s1[1000000+10], s2[10000+10];
int len1, len2;

void get_nextvalval(char* T, int nextvalval[])
{
    int i = 1, j = 0;
    nextvalval[1] = 0;
    while(i < len2) {
        if(j == 0 || T[i] == T[j]) { //使用原始的kmp计算next数组
            ++i;
            ++j;
            //if(T[i] != T[j]) 
                nextvalval[i] = j;
            //else
            //    nextvalval[i] = nextvalval[j];
        } 
        else j = nextvalval[j];
    }
}

int Index_KMP(char* S, char* T, int pos, int nextval[])
{
    int i = pos, j = 1;
    int cnt = 0;
    while(i <= len1 && j <= len2) {
        if(j == 0 || S[i] == T[j]) {
            if(j >= len2) {
                cnt++;
                //printf("%d\n", i);
                j = nextval[j];
            } else {
                ++i;
                ++j;
            }
        }
        else j = nextval[j];
    }    
    return cnt;
}

int main()
{
    int t;
    cin >> t;
    getchar();
    while(t--) {
        memset(s1, 0, sizeof(s1));
        memset(s2, 0, sizeof(s2));
        gets(s2+1);
        gets(s1+1);
        len1 = strlen(s1+1);
        len2 = strlen(s2+1);

        int *nextval = new int[len2+1];

        get_nextvalval(s2, nextval);
        int cnt = 0;
        cnt = Index_KMP(s1, s2, 1, nextval);

        cout << cnt << endl;
        delete[] nextval;
    }
    return 0;
}

如果使用改进kmp,则需要对源代码进行略微的修改。

#include <iostream>
#include <cstring>
using namespace std;
char s1[1000000+10], s2[10000+10];
int len1, len2;

void get_nextvalval(char* T, int nextvalval[])
{
	int i = 1, j = 0;
	nextvalval[1] = 0;
	while(i <= len2) { //改。注意这里的等号
		if(j == 0 || T[i] == T[j]) { //使用原始的kmp计算next数组
			++i;
			++j;
			if(T[i] != T[j]) 
				nextvalval[i] = j;
			else
				nextvalval[i] = nextvalval[j];
		} 
		else j = nextvalval[j];
	}
}

int Index_KMP(char* S, char* T, int pos, int nextval[])
{
	int i = pos, j = 1;
	int cnt = 0;
	while(i <= len1 && j <= len2) {
		if(j == 0 || S[i] == T[j]) {
			i++;
			j++;
			if(j > len2) {
				cnt++;
				//printf("%d\n", i);
				j = nextval[j];
			} 
		}
		else j = nextval[j];
	}    
	return cnt;
}

int main()
{
	freopen("1686.txt", "r", stdin);

	int t;
	cin >> t;
	getchar();
	while(t--) {
		memset(s1, 0, sizeof(s1));
		memset(s2, 0, sizeof(s2));
		gets(s2+1);
		gets(s1+1);
		len1 = strlen(s1+1);
		len2 = strlen(s2+1);

		int *nextval = new int[len2+10];

		get_nextvalval(s2, nextval);
		int cnt = 0;
		cnt = Index_KMP(s1, s2, 1, nextval);

		cout << cnt << endl;
		delete[] nextval;
	}
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值