珍珠项链(kmp)

小H得到了一条珍珠项链,上面有五颜六色的珍珠。小H想知道这条珍珠的价值是多少?
珍珠有从'a'至'z',共26种颜色。珍珠项链的价值为这条珍珠项链前缀出现的次数×该前缀的长度的最大值。

Input

珍珠项链长度1<=N<=100000。
第一行输入一个t,表示测试组数。
接下来t行,每行输入一个字符串。

Output

珍珠的价值

Sample Input

1
aaaa

Sample Output

6

Hint

a出现了4次,4*1=4
aa出现了3次,3*2=6
aaa出现了2次,2*3=6
aaaa出现了1次,1*4=4

思路:

我原本想的是将长度为i-1的起始点保存下来,等下一次枚举到长度为i时,直接看从保存的点与是第i个位置的字符串对比,如果相等,就将这个点保存下来。

但这个时间复杂度最差为o(n^2)。

看的另一篇题解:

kmp,然后从后往前便利,当枚举到i点时,我们用next数组,将以i点为结尾的前缀字符串加到相应位置(ans[next[j]]+=next[j]),最后比较一下ans数组;

(kmp)代码:

#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
#define per(i,a,b) for(int i=a;i<=b;i++)
#define ber(i,a,b) for(int i=a;i>=b;i--)
const int N = 1e5 + 1000;
const double eps = 1e-2;
const int P = 1331;
char s[N];
int ne[N];
int ans[N];
int main()
{
    int T;
    cin >> T;
    while (T--)
    {
        cin >> s + 1;
        int  len = strlen(s + 1);
        for (int i = 2, j = 0; i <= len; i++)
        {
            while (j && s[i] != s[j + 1])j = ne[j];
            if (s[i] == s[j + 1])
                j++;
            ne[i] = j;
        }
        for (int i = 1; i <= len; i++)
        {
            ans[i] = i;
             int j = ne[i];
             while (j) ans[j] += j,j=ne[j];
        }
        int maxx = 0;
        for (int i = 1; i <= len; i++)
            maxx = max(ans[i], maxx);
        cout << maxx << endl;
    }
   
    return 0;
}

你可能感兴趣的:(题解,算法,c++,开发语言)