1005. Programming Pattern (35)

来源:互联网 发布:网络联机小精灵 编辑:程序博客网 时间:2024/05/24 03:28

太菜了,这道题提交了30次,
用后缀数组做,开始用KMP做有一个测试点过不去,
然后学习后缀数组,这是学结构以来学到最崩溃的一次,好多细节没写好,然后错错错

先KMP的做法,就一个节点未过

这里写图片描述

#include<iostream>#include<string>using namespace std;int vv[1048577];int *nextval = (int *)malloc(sizeof(int)* 1048576);void getnext(string &s,int N) {  int i = 0, j = -1;  while (i < N)  {    if (j == -1 || s[i] == s[j])    {      /*++i; ++j;      if (s[i] == s[j]) nextval[i] = nextval[j];      else nextval[i] = j;*/      nextval[++i] = ++j;    }    else      j = nextval[j];  }  for (i = 1; i < N - 1; ++i)    if (s[i] == s[nextval[i]]) nextval[i] = nextval[nextval[i]];}int main(){  int N;  cin >> N;  nextval[0] = -1;   getchar();  string all;  getline(cin, all);  string str1;  int M = 0, M_N = 0;  for (int i = 0; i + N - 1 < all.size();++i)  {    if (all.size() - (i + N - 1) < M) break;    if (vv[i]) continue;    int num = 1;    str1.assign(all, i,  N);    getnext(str1, N);    int pos = i + 1; int j = 0;    while (pos<all.size()) {      if (j == -1 || all[pos] == str1[j]) { ++j; ++pos; }      else j = nextval[j];      if (j == N) {vv[pos - N] = 1; j = nextval[j - 1]; pos--; ++num;  }    }    //cout << str1 << " " << num << endl;    if (num > M||(num==M && all[i]<all[M_N])) {      M = num;      M_N = i;    }  }  cout << string(all, M_N, N) << " " << M << endl;}

再后缀数组的

这里写图片描述

#include<iostream>#include<string>#define MM 1100000using namespace std;char A[MM];//保存字符串1...n//rak[i]代表第i位置的等级,最后也可表示第i位置的排名;second[i],按第二关键字排序,第i名的位置,也暂存上一个过程的rak;//同一等级有相同的权,高等级权大,height[i],表示排名i的串和排名i-1的串最大前缀的字符数sa[i]第i名的位置;vis基排所用的临时数组int rak[MM], second[MM], sa[MM], vis[MM], height[MM];int m, n, w, k;//m代表等级的阶数,n代表串的长度,w代表当前字串长度,k求height所用int N;//输入数据,最终比较串的长度string s;//输入数据,串void initA()//初始化得到数组A,w,m,n,并初始化rak和second{    w = 1;    m = 127;    n = s.size();    for (int i = 1; i <= n; ++i) {        rak[i] = A[i] = s[i - 1];        second[i] = i;    }}void getsecond(){    int p = 0;    //通过sa获得second    for (int i = (n - w + 1) < 1 ? 1 : n - w + 1; i <= n; ++i) second[++p] = i;//****注意越界***********    for (int i = 1; i <= n; ++i) if (sa[i] > w) second[++p] = sa[i] - w;}void getsa()//基排{    //通过第一关键字排名rak,第二关键字排名second,基排得到sa    for (int i = 1; i <= m; ++i) vis[i] = 0;//初始化       for (int i = 1; i <= n; ++i) ++vis[rak[second[i]]];//把所有数据的等级统一放到vis数组中    //求得sa    for (int i = 2; i <= m; ++i) vis[i] += vis[i - 1];    for (int i = n; i >0; --i)  sa[vis[rak[second[i]]]--] = second[i];//**********从n...1**************}bool com(int x, int y) { return second[x] == second[y] && second[x + w] == second[y + w]; }//比较排名相邻的串是否相同void getrak(int flag){    swap(rak, second);//为求新的rak,second暂存上一轮rak数据    int p = 1;    rak[sa[1]] = p;    if (flag) {//得到等级制的rak        for (int i = 2; i <= n; ++i) rak[sa[i]] = com(sa[i], sa[i - 1]) ? p : ++p;    }    else {//得到排名制的rak        for (int i = 2; i <= n; ++i) rak[sa[i]] = i;    }    m = p;}void getheight() {    //for (int i = 1; i <= n; ++i) cout << string(s, sa[i] - 1, n - sa[i]+1) << endl;    k = 0;    for (int i = 1; i <= n; height[rak[i++]] = k) {        if (k) --k;        for (int j = sa[rak[i] - 1]; A[i + k] == A[j + k];) {            if (++k >= N) {                k = N; break;            }        }    }}int main(){    cin >> N; getchar();    getline(cin, s);    initA();    getsa();    while (1) {        getsecond();        getsa();        getrak(1);        if (w >= N) break;        w += w;    }    getrak(0);    getheight();    //求结果    int g = 1, h = sa[1];//过程数据,临时存放相同串个数和其某个串的第一字符位置    int re_g = 1, _h = 1;//存放结果    for (int i = 2; i <= n; ++i) {        if (height[i] >= N) {            ++g;        }        else {            if (g > re_g || (g == re_g && s[h - 1] < s[_h - 1])) {                re_g = g; _h = h;            }            g = 1; h = sa[i];        }    }    if (g > re_g || (g == re_g && s[h - 1] < s[_h - 1])) {//最后的比较        re_g = g; _h = h;    }    cout << string(s, _h - 1, N) << " " << re_g << endl;}
原创粉丝点击