KMP匹配问题、求字符串的周期、Cyclic Nacklace

来源:互联网 发布:html5 javascript 联系 编辑:程序博客网 时间:2024/06/06 20:57

本文中一共有3个问题,一共有3个求next的方法。

问题一,KMP匹配问题,用的是精确(高效)的求next的方法(来自紫红色的清华大学数据结构课本)

问题二,求字符串的周期,用的是自己写的求next的方法

问题三,求构成有周期的字符串至少需要补多少字符,用的是普通的求next的方法(也来自上述课本)

三个问题都已经AC了,下面贴出来的代码也都是AC了的。

然而,问题二的代码中的next,只能用来求周期,如果用来KMP匹配果断错敲打

看来我对KMP仍然很不熟悉,如果本文有错误,欢迎指正!

精确的和普通的,效率是不一样的,一个是θ(m+n),一个是O(m*n)

也就是说,普通的next在匹配aaaaaaaaaaaaaaaaaaaa和aaaab的时候效率是很低的,

精确的next处理掉了这个问题,但同时也失去了短串本身的周期性质。


KMP匹配问题

题目:

Description

Given two sequences of numbers : a[1], a[2], ...... , a[N], and b[1], b[2], ...... , b[M] (1 <= M <= 10000, 1 <= N <= 1000000). Your task is to find a number K which make a[K] = b[1], a[K + 1] = b[2], ...... , a[K + M - 1] = b[M]. If there are more than one K exist, output the smallest one. 

Input

The first line of input is a number T which indicate the number of cases. Each case contains three lines. The first line is two numbers N and M (1 <= M <= 10000, 1 <= N <= 1000000). The second line contains N integers which indicate a[1], a[2], ...... , a[N]. The third line contains M integers which indicate b[1], b[2], ...... , b[M]. All integers are in the range of [-1000000, 1000000]. 

Output

For each test case, you should output one line which only contain K described above. If no such K exists, output -1 instead. 

Sample Input

213 51 2 1 2 3 1 2 3 1 3 2 1 21 2 3 1 313 51 2 1 2 3 1 2 3 1 3 2 1 21 2 3 2 1

Sample Output

6-1

我本来是自己写的求next的方法,可惜最后超时了,我测试了一下,这个在最坏情况下确实是暴力的敲打

我们课本上面写了2个求next数组的方法,第一个和我自己写的是一样的,第2个就是专门解决listm为1 1 1 1 1 1 2这种情况的。

于是我直接把第2个改进后的方法抄下来。。。

代码:

#include<iostream>#include<string.h>using namespace std;int listn[1000001];//长串int listm[10001];//短串int next_[10001];void getnext(int *t,int m, int *next)//m是短串t的长度{int i = 1, j = 0;next[1] = 0;while (i < m){if (j == 0 || t[i] == t[j]){i++;j++;if (t[i] != t[j])next[i] = j;else next[i] = next[j];}else j = next[j];}}int main(){ios_base::sync_with_stdio(false);//减小输入输出的时间int t, n, m;cin >> t;while (t--){cin >> n >> m;for (int i = 1; i <= n; i++)cin >> listn[i];for (int i = 1; i <= m; i++)cin >> listm[i];listm[0] = 2000000;next_[0] = 0;next_[1] = 0;int i,j;getnext(listm, m, next_);i = 1;j = 1;while (i <= n){if (listn[i] == listm[j]){i++;j++;if (j > m)break;}else{if (next_[j])j = next_[j];else{i++;j = 1;}}}if (j > m)cout << i - m;else cout << -1;cout << endl;}return 0;}

求字符串的周期

题目:

Description

Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc" and b = "def" then a*b = "abcdef". If we think of concatenation as multiplication, exponentiation by a non-negative integer is defined in the normal way: a^0 = "" (the empty string) and a^(n+1) = a*(a^n).

Input

Each test case is a line of input representing s, a string of printable characters. The length of s will be at least 1 and will not exceed 1 million characters. A line containing a period follows the last test case.

Output

For each s you should print the largest n such that s = a^n for some string a.

Sample Input

abcdaaaaababab.

Sample Output

143

这个题目的next数组就是我自己写代码求的,在求上一个问题时候写的,只不过没用上。

不过本题不能用上题那种精确的求next的方法,a b c a b c a b c a b c的next是011 011 011 011

好像也可以用来求周期,但是肯定没有下面的方法这么简单。

下面的方法,根据dif差不多就直接求出来了。

dif = l - next_[l]

代码:

#include<iostream>#include<string.h>using namespace std;char c[1000001];int next_[1000001];int l;int main(){while (1){gets(c+1);l = strlen(c+1);if (l == 1 && c[1] == '.')break;next_[0] = 0;next_[1] = 0;int i, j;for (i = 2; i <= l; i++){j = i - 1;while (j && c[j] != c[next_[j]])j = next_[j];next_[i] = next_[j] + 1;}int dif = l - next_[l];if (next_[l] == 1){if (l > 1)cout << 1;else cout << l;}else if (l%dif){cout << 1;}else{if (c[l] == c[next_[l]])cout << l/dif;else cout << 1;}cout << endl;}return 0;}

这个代码是AC了的,对于求周期确实是有效的。

但是!求出来的数组next居然是错的!

我在AC之前只关注如何用next求周期,AC之后仔细一想,有问题!

比如输入aaabbbaaa,求的next居然是012333343。。。

也就是说,我写错了,这个数组确实记录了字符串的周期信息,然而却没法拿去匹配。

虽然不影响本题的AC,但是知道这个结果还是感觉自己好low啊哭


Cyclic Nacklace(求构成有周期的字符串至少需要补多少字符)

题目:

Description

CC always becomes very depressed at the end of this month, he has checked his credit card yesterday, without any surprise, there are only 99.9 yuan left. he is too distressed and thinking about how to tide over the last days. Being inspired by the entrepreneurial spirit of "HDU CakeMan", he wants to sell some little things to make money. Of course, this is not an easy task. 

As Christmas is around the corner, Boys are busy in choosing christmas presents to send to their girlfriends. It is believed that chain bracelet is a good choice. However, Things are not always so simple, as is known to everyone, girl's fond of the colorful decoration to make bracelet appears vivid and lively, meanwhile they want to display their mature side as college students. after CC understands the girls demands, he intends to sell the chain bracelet called CharmBracelet. The CharmBracelet is made up with colorful pearls to show girls' lively, and the most important thing is that it must be connected by a cyclic chain which means the color of pearls are cyclic connected from the left to right. And the cyclic count must be more than one. If you connect the leftmost pearl and the rightmost pearl of such chain, you can make a CharmBracelet. Just like the pictrue below, this CharmBracelet's cycle is 9 and its cyclic count is 2: 

Now CC has brought in some ordinary bracelet chains, he wants to buy minimum number of pearls to make CharmBracelets so that he can save more money. but when remaking the bracelet, he can only add color pearls to the left end and right end of the chain, that is to say, adding to the middle is forbidden. 
CC is satisfied with his ideas and ask you for help.

Input

The first line of the input is a single integer T ( 0 < T <= 100 ) which means the number of test cases. 
Each test case contains only one line describe the original ordinary chain to be remade. Each character in the string stands for one pearl and there are 26 kinds of pearls being described by 'a' ~'z' characters. The length of the string Len: ( 3 <= Len <= 100000 ).

Output

For each case, you are required to output the minimum count of pearls added to make a CharmBracelet.

Sample Input

3aaaabcaabcde

Sample Output

025


代码:

#include<iostream>#include<string.h>using namespace std;char c[100005];int next_[100005];int l;void get_next(char *t, int m, int next[]){int i = 1, j = 0;next[1] = 0;while (i < m){if (j == 0 || t[i] == t[j])next[++i] = ++j;else j = next[j];}}int main(){int t;cin >> t;gets(c + 1);while (t--){gets(c + 1);l = strlen(c + 1);next_[0] = 0;next_[1] = 0;int i, j;get_next(c, l, next_);int dif = l - next_[l];if (c[l] == c[next_[l]])cout << (dif - l%dif) % dif;else cout << l;cout << endl;}return 0;}


这个分类,简单的吓人啊。

当然了,这是我把代码重写之后的样子,第一次AC的时候自然不是这个样子(我也写不出这么变态的表达式啊)

2 0
原创粉丝点击