suffix array的 相关知识及利用doubling algorithm构建原理详见

http://download.csdn.net/detail/wmj75617718/6724275

以下代码是根据上面的资源完成,加了部分注释和补充

#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define MAXN 1000001
int wa[MAXN],wb[MAXN],wv[MAXN],ws[MAXN];int cmp(int *r, int a, int b, int l)
{return r[a] == r[b] && r[a + l] == r[b + l];
}/* douling algrithm 求字符串r的后缀数组,r最后一个字符是人为设定的0('\0'),* 后缀数组sa实际从sa[1]还是有效(sa[0]就是那个人为设定的0)*/
void CalSA(int *r, int *sa, int n, int m)
{int i, j, p, *x = wa, *y = wb, *t;// 各个后缀按第一个字符排序, 计数排序for(i = 0; i < m; i++) ws[i] = 0;for(i = 0; i < n; i++)ws[x[i] = r[i]]++;for(i = 1; i < m; i++)ws[i] += ws[i - 1];for(i = n - 1; i >= 0; i--)sa[--ws[x[i]]] = i;for(j = 1, p = 1; p < n; j *= 2, m = p) {// 各个后缀按前j + 1个字符排序,基数排序// 各个后缀按第二关键字排序for(p = 0, i = n - j; i < n; i++)y[p++] = i;for(i = 0; i < n; i++) {if(sa[i] >= j)y[p++] = sa[i] - j;}// 各个后缀按第一关键字排序,计数排序for(i = 0;i < n; i++)wv[i] = x[y[i]];for(i = 0; i < m; i++)ws[i] = 0;for(i = 0; i < n; i++)ws[wv[i]]++;for(i = 1; i < m; i++)ws[i] += ws[i-1];for(i = n - 1; i >= 0; i--)sa[--ws[wv[i]]] = y[i];// 计算名次数组x,前j + 1个字符相同的后缀名次相同for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i++)x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++;}return;
}int rank[MAXN], height[MAXN];/* 求名次相邻的两个后缀之间的最长公共前缀(lcp)* height[i] = lcp(suffix(sa(i)), suffix(sa(i - 1)))*/
void CalHeight(int *r,int *sa,int n)
{int i, j, k = 0;for(i = 1; i <= n; i++)rank[sa[i]] = i;for(i = 0; i < n; height[rank[i++]] = k) {for(k?k--:0, j = sa[rank[i] - 1]; r[i + k] == r[j + k]; k++);}return;
}int log2[MAXN];
int dpmin[MAXN][20];
void InitRMQ(int n)
{// log2[i]等于满足条件 2^k < i(k为大于等于0的整数) 的最大k值// 亦即log2[i]就是小于等于LOG2(i)的最大整数log2[0] = -1;for(int i = 1; i <= n; i++)log2[i] = ((i & (i - 1)) == 0) ? log2[i - 1] + 1 : log2[i - 1];// dpmin[i][j]代表RMQ中在[i, i + 2^j - 1]区间范围内最小的元素IDfor(int i = 1; i <= n; i++)dpmin[i][0] = i;for(int j = 1; j <= log2[n]; j++) {for(int i = 1; i <= n + 1 - (1 << j); i++) {int tmp1 = dpmin[i][j - 1];int tmp2 = dpmin[i + (1 << (j - 1))][j - 1];if(height[tmp1] < height[tmp2]) dpmin[i][j] = tmp1;else dpmin[i][j] = tmp2;}}return;
}/* 求RMQ中[a, b]区间范围内最小的元素ID*/
int AskRMQ(int a, int b)
{int tmp;tmp = log2[b - a + 1];b = b - (1 << tmp) + 1;a = dpmin[a][tmp];b = dpmin[b][tmp];return height[a] < height[b] ? a : b;
}/* 计算后缀 suffix(a) 和 suffix(b) 的最长公共前缀(lcp)* a不能等于b*/
int CalLcp(int a,int b)
{a = rank[a];b = rank[b];if(a > b) {int tmp;tmp = a;a = b;b = tmp;}return height[AskRMQ(a + 1, b)];
}int main()
{int r[256], sa[256];const char *str = "abcabdabcddabd";for (int i = 0; i <= strlen(str); i++)r[i] = str[i];CalSA(r, sa, strlen(str) + 1, 'z' + 1);for (int i = 1; i <= strlen(str); i++)printf("%d: %s\n", sa[i], str + sa[i]);CalHeight(r, sa, strlen(str));for (int i = 1; i <= strlen(str); i++)printf("%d\n", height[i]);InitRMQ(strlen(str));printf("CalLcp: %d, %d, %d\n", CalLcp(0, 6), CalLcp(3, 9), CalLcp(3, 6));return 0;
}

doubling algorithm 构建后缀数组 code相关推荐

  1. [bzoj3879]SvT_后缀数组_RMQ_单调栈

    SvT bzoj-3879 题目大意:给定一个字符串.每次询问给定$t$个位置,求两两位置开头的后缀的$LCP$之和. 注释:$1\le length\le 5\cdot 10^5$,$\sum t\ ...

  2. Boring counting HDU - 3518 (后缀数组)

    Boring counting \[ Time Limit: 1000 ms \quad Memory Limit: 32768 kB \] 题意 给出一个字符串,求出其中出现两次及以上的子串个数,要 ...

  3. 【算法与数据结构】——后缀数组

    参考后缀数组 基数排序 后缀数组的实现用到了基数排序,简单介绍一下基数排序的内容. 基数排序是桶排序的一种扩展,是一种多关键字的排序方法.若记录按照多个关键字排序,则依次按照这些关键字进行排序. 例如 ...

  4. 算法笔记——后缀数组

    后缀指从某个位置开始到字符串末尾的一个子串,用suffix(i)来表示. 后缀数组(suffix array)指将s的所有后缀从小到大排序后,取其下标i放入数组中,该数组就叫做后缀数组. 表示排名为i ...

  5. 使用倍增算法(Prefix Doubling)构造后缀数组

    如果采用对每个后缀排序的方法来生成后缀数组,即使采用快速排序,由于每次比较的对象是字符串(设输入字符串的长度为n),因此每一个比较操作的复杂度不再是常数,而是O(n),快速排序本身的平均情况下时间复杂 ...

  6. 构建乘积数组[前后缀优化]

    前后缀 前言 一.构建乘积数组 二.前后缀 1.前后缀直接相乘 2.状态压缩 总结 参考文献 前言 前后缀是一种典型的空间换时间的做法,通过记录每个位置的状态来达到减少计算,而且当有前后遍历时,还可以 ...

  7. 后缀数组的倍增算法(Prefix Doubling)

    最近在自学BWT算法(Burrows-Wheeler transform),其中涉及到对字符串循环移位求编码.直观的办法就是模拟,使用O(n3)的时间求出BWT编码.经过简单的简化后也要O(n2log ...

  8. 树链剖分 + 后缀数组 - E. Misha and LCP on Tree

    E. Misha and LCP on Tree Problem's Link Mean: 给出一棵树,每个结点上有一个字母.每个询问给出两个路径,问这两个路径的串的最长公共前缀. analyse: ...

  9. 后缀数组总结(转载)

    后缀数组--处理字符串的有力工具 作者:罗穗骞 2009年1月 [摘要] 后缀数组是处理字符串的有力工具.后缀数组是后缀树的一个非常精巧的替代品,它比后缀树容易编程实现,能够实现后缀树的很多功能而时间 ...

最新文章

  1. OpenStack 实现技术分解 (6) 通用库 — oslo_log
  2. 【Socket】linux广播技术
  3. pat德才论(java)
  4. tensorflow dataset_ops shuffle()方法 (随机重新排列此数据集的元素)
  5. 论面向对象方法与软件复用关系-z
  6. JavaSE基础知识学习-----泛型
  7. python合并两个excel文件_利用Python将多个excel文件合并为一个文件
  8. uboot环境变量(设置bootargs向linux内核传递正确的参数)
  9. html可编辑下拉选项卡,bootstrap可编辑下拉框jquery.editable-select
  10. 在Android手机上对https请求进行抓包
  11. 微搭自定义组件库开发环境搭建教程
  12. 拼多多出现重大BUG,几小时内损失超千万,但处理方式让用户怒了
  13. php获取今天星期几,PHP获取星期几的常用方法小结
  14. [ctf web][csaw-ctf-2016-quals]mfw writeup
  15. 蓝桥--不同非空子串
  16. 论文阅读-----使用可分离脚印的x射线3D CT向前和向后投影
  17. 如果一觉醒来已是光年之远
  18. ElementUI 表单单个验证
  19. ajax获取涨停股票接口,80后股神研究的两个涨停买入法!(图解)
  20. 充电桩设计之电川 充电板的驱动控制程序

热门文章

  1. 我为什么不推荐用fmt.Sprintf
  2. 利用宏文件提取SolidWorks草图中点的坐标
  3. 长沙理工计算机竞赛黑马,从“清北摇篮”到学科竞赛全国200强,安居育才成为最大黑马!...
  4. wcf 返回图片_WCF开山篇__图片传输
  5. verilog 赋值
  6. [安洵杯 2019]iamthinking
  7. java dag_如何在Java中实现类似DAG的调度程序?
  8. Java开发环境实验报告,太香了
  9. Redis-- 缓存预热+缓存雪崩+缓存击穿+缓存穿透
  10. 关于正确追讨工资的七个途径!