算法刷题记录(Day 34)

Period(poj 1961)

原题链接
题目类型:KMP最小重复子串

#include<iostream>
#include<string>
using namespace std;
#define NMAX  1000100
char s[NMAX];
int Lat[NMAX];
int N;
void get_Lat(int* Lat, char* s2, int lens) {
    //用于构建s2的Lat数组,kmp的前奏
    int t1 = 0, t2;
    Lat[0] = t2 = -1;
    while (t1 < lens) { //逐步向前寻找t2
        if (t2 == -1 || s2[t1] == s2[t2]) {
            Lat[t1 + 1] = t2 + 1;
            t1++;
            t2++; //t2首先指向的是Lat[t1-1]即前一个的位置
        }
        else t2 = Lat[t2]; //保证了0 与t1-1等对的一致,若出现了不等,则会直接
    }
}
int main() {
    int num = 1;
    while(1) {
        cin >> N;
        if (!N) break;
        cin >> s;
        get_Lat(Lat, s, N);
       // for (int i = 1; i < strlen(s); i++) cout << Lat[i] << " ";
        cout << "Test case #"<<num++<<endl;
        for (int i = 2; i <= N; i++) {
            //cout << "length"<<strlen(s) << endl;
            int start = i;
            int standard = start - Lat[start];
            if (i % standard == 0 && i / standard>1) cout << i << " " << i / standard << endl;
        }
        cout << endl;
    }
}


tip:
1.如果在循环中使用i<=strlen(s)的话会出现超时错误 (tle警告)
2.在对该题的求解过程中,应该去推导得到关于最小重复子串个数的公式,若依据nxt数组逐步向前遍历的话,会超时。

Oulipo(poj 2406)

原题链接
题目类型:KMP字符串匹配

#include<iostream>
#include<string>
using namespace std;
#define WMAX  10010
#define TMAX  1000010
char W[WMAX];
char T[TMAX];
int nxt[TMAX];
int tl, wl;
int N;
int num;
void get_Lat(int* nxt, char* s, int lens) {
	nxt[0] = -1;
	int t1 = 0, t2 = -1;
	while (t1 < lens) {
		if (t2 == -1 || s[t1] == s[t2]) {
			nxt[t1 + 1] = t2 + 1;
			t1++;
			t2++;
		}
		else t2 = nxt[t2];
	}
}
int main() {
	cin >> num;
	while (num--) {
		//scanf_s("\n%s\n%s", W, T);
		int times = 0;
		cin >> W >> T;
		tl = strlen(T), wl = strlen(W);
		get_Lat(nxt, W, wl);
		int t1 = 0, t2 = 0;
		while (t1 < tl && t2 < wl) {
			if (t2==-1 || T[t1] == W[t2]) {
				t1++, t2++;
			}
			else t2 = nxt[t2]; //注意这里仅和W串有关系
			if (t2 == wl) {
				times++;
				t2 = nxt[t2];//注意在能够进行一个完全的匹配后应该对t2进行更新
			}
		}
		cout << times << endl;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值