后缀数组学习ing

来源:互联网 发布:mac如何剪辑音频文件 编辑:程序博客网 时间:2024/06/06 19:38

学习后缀数组。

宽宽发我一份英文网页,说讲的很好,于是我忍痛翻译了一晚上,卒。

第二天早上对着网页一脸懵,虽然思路什么的写的很好,简单易懂,但是那个代码实在是。。还敢更难懂一些嘛!!!想了想,还是问问卿爷吧orz

卿爷以一脸不可描述的表情给我讲了一早上后缀数组,总算明白了后缀数组究竟是啥,代码究竟是啥。期间多次差点把卿爷气死【赶紧跑】不过还是毅然决然抱着被卿爷骂死也得听懂的觉悟,看着卿爷一脸不可描述+很无奈的表情,一边顺毛一边继续听。

最后卿爷即兴发问,还好都答出来了,不然感觉已经无法在这里写博客了2333

不过后缀数组的裸题【求最长公共子串】卿爷讲了两遍我还是略模糊,看来还得翻翻大神们的博客才行。

继续修炼ing

flag不能立,要做的事情,就要自己记得啦


贴个卿爷教的模板,感觉卿爷讲过之后再看觉得好懂多了,做题做题,先过了裸题再说。。。


#include <stdio.h>#include <math.h>#include <string.h>#include <algorithm>#include <queue>#include <iostream>#include <assert.h>#define INF 0x3f3f3f3fusing namespace std;const int maxn = 1e6 + 10;int w[maxn];  //神奇的数组,桶排序所用,把每个字符丢到桶里int rankk[maxn * 2];  //rank数组,与sa数组互逆,要开长度的两倍,因为排序用到了rank[i+k]int sa[maxn];  //sa数组,嗯,写不清楚。。后缀数组里一个很神奇的数组int height[maxn]; //记录最长公共前缀char s[maxn]; //输入的字符串//rankk,sa,height,都是从1存到len,0的位置不参与void get_sa_hei(){  static int m[maxn], tmp[maxn];  //辅助数组,基数排序算rank和height用到  int len = strlen(s + 1);  //len为字符串长度,字符串位置从1-len  memset(rankk, 0, sizeof(int) * len * 2);  for (int i = 0; i <= 255; i++) w[i] = 0; //最小要写255,以防爆炸(什么爆炸来着。。反正要开大点。。)  for (int i = 1; i <= len; i++) w[s[i]]++; //把每个字母都丢进去  for (int i = 1; i <= 255; i++) w[i] += w[i - 1]; //算前缀和,得出每个字母的位置  for (int i = len; i; i--) tmp[w[s[i]]--] = i; //  rankk[tmp[1]] = 1; //  //如果相等,rank一样,若是不等,rank值+1,与下面注释等价  for (int i = 2; i <= len; i++)    rankk[tmp[i]] = rankk[tmp[i-1]] + (s[tmp[i]] != s[tmp[i-1]]);//    if (s[tmp[i]] != s[tmp[i-1]])//        rankk[tmp[i]] = rankk[tmp[i-1]] + 1;//    else//      rankk[tmp[i]] = rankk[tmp[i-1]];  ///get sa  用基数排序  for (int k = 1; k <= len; k <<= 1) {    for (int i = 0; i <= len; i++) w[i] = 0;    for (int i = 1; i <= len; i++) w[rankk[i+k]]++;    for (int i = 1; i <= len; i++) w[i] += w[i-1];    for (int i = len; i; i--) m[w[rankk[i+k]]--] = i;    for (int i = 0; i <= len; i++) w[i] = 0;    for (int i = 1; i <= len; i++) w[rankk[i]]++;    for (int i = 1; i <= len; i++) w[i] += w[i-1];    for (int i = len; i; i--) tmp[w[rankk[m[i]]]--] = m[i];    m[tmp[1]] = 1;    for (int i = 2; i <= len; i++) //最开始只有一个,这时有两个需要考虑      m[tmp[i]] = m[tmp[i-1]] + (rankk[tmp[i]] != rankk[tmp[i-1]] || rankk[tmp[i]+k] != rankk[tmp[i-1]+k]);//      if (rankk[tmp[i]] != rankk[tmp[i-1]] || rankk[tmp[i]+k] != rankk[tmp[i-1]+k])//        m[tmp[i]] = m[tmp[i-1]] + 1;//      else//        m[tmp[i]] = m[tmp[i-1]];   //跟上面那句等价//卿爷说那样优美,不过那一句代码好长,超过了学霸划的线,感觉美感没了。。    for (int i = 1; i <= len; i++) rankk[i] = m[i];  }  for (int i = 1; i <= len; i++) sa[rankk[i]] = i; //sa数组到此求出  //本来是没有tmp数组的,直接写的是sa,卿爷说感觉那样写还是不好,所以又定义了tmp数组  //其实我也觉得,最后一遍赋值感觉更清晰明朗一些  //比起sa和rank都变,我比较倾向于一个变,一个最后求  //就是这么蠢,咬我啊【略略略】  ///get height  一个很神奇的写法(卿爷前辈们的优化  //模模糊糊明白一些,但是看着真的很优美啊!  for (int i = 1, j = 0; i <= len; i++) {    if (rankk[i] == 1) continue;    for (j ? j-- : 0; s[sa[rankk[i]-1]+j] == s[i+j]; j++);     height[rankk[i]] = j;  }}int main(){  while (scanf("%s", s + 1)) {    get_sa_hei();    int len = strlen(s + 1);    for (int i = 1; i <= len; i++) {      cout << sa[i] << "~~~" << height[i] << endl;    }  }  return 0;}


0 0
原创粉丝点击