学习了后缀数组,顺便把DC3算法也看了一下,传说中可以O(n)复杂度求出文本串的height,先比较一下倍增算法和DC3算法好辣。

      DC3          倍增法

时间复杂度 O(n)(但是常数很大)     O(nlogn)(常数较小)

空间复杂度   O(n)            O(n) 

编程复杂度    较高            较低

  由于在时间复杂度上DC3的常数比较大,再加上编程复杂度比较高,所以在解决问题的时候并不是最优选择。但是学到了后缀数组还是补充一下的好点。

  DC3算法的实现:

  1:先把文本串的后缀串分成两部分,第一部分是后缀串i mod 3 == 0, 第二部分是i mod 3 != 0,然后先用基数排序对第二部分后缀串排序(按照前三个字符进行排序)。

 int *san = sa+n, *rn = r+n, ta=, tb=(n+)/, tbc=, i, j, p;
//ta i mod 3==0的个数,tb i mod 3==1的个数, tbc imod3!=0的个数
for (i=; i<n; i++)
if (i % )
x[tbc ++] = i; r[n] = r[n+] = ;//在文本串后面添加两个0,便于处理
Sort (r+, x, y, tbc, m);
Sort (r+, y, x, tbc, m);
Sort (r, x, y, tbc, m);

  然后把suffix[1]与suffix[2]数组连起来,每三个相邻的字符看做一个数,变成这个样子:

操作代码如下:

 rn[F(y[])] = ;
for (i=, p=; i<tbc; i++)
rn[F(y[i])] = c0(r, y[i-], y[i])?p-:p++;
//#define F(x) x/3+(x%3==1?0:tb)
//F(x) 求原字符串suffix(i)在新串中的位置

如果p>=tbc的话,也就是说只排列前三个字符就可以区分出第二部分后缀串的顺序了,否则就要进行递归继续对第二部分的串进行排序。

 if (p < tbc)
DC3 (rn, san, tbc, p);
else
for (i=; i<tbc; i++)
san[rn[i]] = i;

  2:对第一部分后缀来说:

  suffix[3*i] = r[3*i] + suffix[3*i+1];

  suffix[3*j] = r[3*j] + suffix[3*j+1]; 我们已知i mod 3 == 1 的所有suffix[i]的顺序了,可以利用基数排序很快的求出第一部分后缀的顺序。

 for (i=; i<tbc; i++)
if (san[i] < tb)
y[ta++] = san[i]*;
if (n% == )
//对于n%3==1时,不存在suffix[n-1] == r[n] + suffix[n];
y[ta++] = n - ;
Sort (r, y, x, ta, m);//对mod3==0的后缀串排序

  3:第一部分后缀数组和第二部分后缀数组都排好序以后,可以对两部分后缀数组进行一次简单的归并排序,然后sa数组就完美呈现了。

 //#define G(x) x>=tb?(x-tb)*3+2:x*3+1
//新文本串中suffix(i)在原文本串中的位置
for (i=; i<tbc; i++)
c[y[i] = G(san[i])] = i;
for (i=, j=, p=; i<ta&&j<tbc; p++)
sa[p] = c12 (y[j]%, r, y[j], x[i])?y[j++]:x[i++];
for (; j<tbc; j++)
sa[p++] = y[j];
for (; i<ta; i++)
sa[p++] = x[i];

c12就是比较第一部分与第二部分串的大小:

suffix [3*i] = r[3*i] + suffix[3*i+1];

suffix [3*j+1] = r[3*j+1] + suffix[3*j+2]; 已知suffix[3*i+1]与suffix[3*i+2]所对应的大小关系,可以比较r[3*i]与r[3*j+1]的大小得出最终结果。

suffix [3*i] = r[3*i] + suffix[3*i+1];

suffix [3*j+2] = r[3*j+2] + suffix[3*(j+1)]; 这个我们可以先比较 r[3*i] 与 r[3*j+2] 的大小,然后再比较 suffix[3*i+1] 与 suffix[3*(j+1)] ,这样就把问题转化为了第一种情况咯。

 bool c12 (int k, int *r, int a, int b)
{//return 真 suffix[b]大,return false suffix[a]大
if (k == )
return r[a]<r[b] || (r[a]==r[b]&&c[a+]<c[b+]);
return r[a]<r[b] || (r[a]==r[b]&&c12(, r, a+, b+));
}

对于和后缀数组相关的这两个算法,其实并没有什么难点。难理解的点就在于基数排序对数组的使用,手动模拟几遍就OK辣!

最后再附上一个完整的DC3代码

 #define F(x) x/3+(x%3==1?0:tb)
#define G(x) x>=tb?(x-tb)*3+2:x*3+1 const int maxn = ;
int c[maxn*], x[maxn*], y[maxn*];
int sa[maxn*], rank[maxn*]; bool c0 (int *r, int a, int b)
{
return r[a]==r[b] && r[a+]==r[b+] && r[a+]==r[b+];
} bool c12 (int k, int *r, int a, int b)
{
//return 真 suffix[b]大,return false suffix[a]大
if (k == )
return r[a]<r[b] || (r[a]==r[b]&&c[a+]<c[b+]);
return r[a]<r[b] || (r[a]==r[b]&&c12(, r, a+, b+));
} void Sort (int *r, int *a, int *b, int n, int m)
{
for (int i=; i<m; i++) c[i] = ;
for (int i=; i<n; i++) c[r[a[i]]] ++;
for (int i=; i<m; i++) c[i] += c[i-];
for (int i=n-; i>=; i--)
b[--c[r[a[i]]]] = a[i];
} void DC3 (int *r, int *sa, int n, int m)
{
int *san = sa+n, *rn = r+n, ta=, tb=(n+)/, tbc=, i, j, p;
for (i=; i<n; i++) if (i % ) x[tbc ++] = i; r[n] = r[n+] = ;
Sort (r+, x, y, tbc, m);
Sort (r+, y, x, tbc, m);
Sort (r, x, y, tbc, m); rn[F(y[])] = ;
for (i=, p=; i<tbc; i++)
rn[F(y[i])] = c0(r, y[i-], y[i])?p-:p++;
//rn[i] 起始位置为i的排名 if (p < tbc)
DC3 (rn, san, tbc, p);
else
for (i=; i<tbc; i++)
san[rn[i]] = i; for (i=; i<tbc; i++)
if (san[i] < tb)
y[ta++] = san[i]*; if (n% == )
y[ta++] = n - ; Sort (r, y, x, ta, m);//对mod3==0的后缀串排序
for (i=; i<tbc; i++)
c[y[i] = G(san[i])] = i; for (i=, j=, p=; i<ta&&j<tbc; p++)
sa[p] = c12 (y[j]%, r, y[j], x[i])?y[j++]:x[i++];
for (; j<tbc; j++)
sa[p++] = y[j];
for (; i<ta; i++)
sa[p++] = x[i]; return;
}

后缀数组 DC3构造法 —— 详解的更多相关文章

  1. [八分之一的男人]POJ - 1743 后缀数组 height分组 带详解

    题意:求最长不可重叠的相同差值子串的长度 这道题算是拖了好几个月,现在花了点时间应该搞懂了不少,尝试分析一下 我们首先来解决一个退化的版本,求最长不可重叠的相同子串(差值为0) 比如\(aabaaba ...

  2. RAII惯用法详解

    [1]什么是RAII惯用法? RAII是Resource Acquisition Is Initialization的缩写,意为“资源获取即初始化”. 它是C++之父Bjarne Stroustrup ...

  3. GoLang基础数据类型--->数组(array)详解

    GoLang基础数据类型--->数组(array)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Golang数组简介 数组是Go语言编程中最常用的数据结构之一.顾名 ...

  4. 数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解

    数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解 对数组有不了解的可以先看看我的另一篇文章,那篇文章对数组有很多详细的解析,而本篇文章则着重讲动态数组,另一篇文章链接 ...

  5. POJ - 2406 Power Strings (后缀数组DC3版)

    题意:求最小循环节循环的次数. 题解:这个题其实可以直接用kmp去求最小循环节,然后在用总长度除以循环节.但是因为在练后缀数组,所以写的后缀数组版本.用倍增法会超时!!所以改用DC3法.对后缀数组还不 ...

  6. C语言 后缀自增的优先级详解

    // ++ 后缀自增与取地址& ,提领 * (指针里的操作符)的优先级比较 #include<stdio.h> #include<stdlib.h> #include& ...

  7. POJ 3581 Sequence ——后缀数组 最小表示法

    [题目分析] 一见到题目,就有了一个显而易见obviously的想法.只需要每次找到倒过来最小的那一个字符串翻转就可以了. 然而事情并不是这样的,比如说505023这样一个字符串,如果翻转了成为320 ...

  8. 中文分词系列(一) 双数组Tire树(DART)详解

    1 双数组Tire树简介 双数组Tire树是Tire树的升级版,Tire取自英文Retrieval中的一部分,即检索树,又称作字典树或者键树.下面简单介绍一下Tire树. 1.1 Tire树 Trie ...

  9. SLAM入门之视觉里程计(6):相机标定 张正友经典标定法详解

    想要从二维图像中获取到场景的三维信息,相机的内参数是必须的,在SLAM中,相机通常是提前标定好的.张正友于1998年在论文:"A Flexible New Technique fro Cam ...

随机推荐

  1. 在MVC中使用泛型仓储模式和工作单元来进行增删查改

    原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-operations-using-the-generic-repository-pat ...

  2. ERROR 1366 (HY000): Incorrect string value: '\xD6\xD0\xCE\xC4' for column XXX at row 1

    本错误为:该列的插入格式有误 修改该表中该列的字符集为utf-8 网上办法: )不能插入中文解决办法: 向表中插入中文然后有错误. mysql> insert into users values ...

  3. 20170218 OO-ALV标准工具栏按钮

    原文地址:OO ALV 工具栏对于的功能码   图标与对应的 功能码 明细 &DETAIL 检查 &CHECK 刷新 &REFRESH 剪切 &LOCAL&CU ...

  4. Spring的声明式事务

    1.与hibernate集成 <bean id="sessionFactory" class="org.springframework.orm.hibernate3 ...

  5. MySQL安装、安装时未提示输入密码、如何修改密码小结

    http://blog.csdn.net/fr555wlj/article/details/54971412

  6. linux初级学习笔记二:linux操作系统及常用命令,文件的创建与删除和命名规则,命令行展开以及linux中部分目录的作用!(视频序号:02_3)

    本节学习的命令:tree,mkdir,rmdir,touch,stat,rm 本节学习的技能:Linux中主要的目录作用以及特殊的目录文件: 文件的命名规则,命令行展开: 文件的创建与删除: Linu ...

  7. codeforces 667D D. World Tour(最短路)

    题目链接: D. World Tour time limit per test 5 seconds memory limit per test 512 megabytes input standard ...

  8. 基于jQuery仿淘宝产品图片放大镜特效

    在开发商城的时候,往往会用到图片的放大功能,这里把自己在近期项目中使用的放大镜特效做一下总结(非插件). 放大镜效果 常用的js组件jquery.imagezoom,jquery.jqzoom,jqu ...

  9. 「LuoguT36048」 Storm in Lover

    Description 平成二十四年(2012年),5月11日,东京,某弓道场. "呐,呐,海未酱,你听说了吗?几天后的那场弓道大会?啊-!"橙发少女兴奋地拿着一张传单一样的纸跑向 ...

  10. 【JSOI 2007】建筑抢修

    [题目链接] 点击打开链接 [算法] 将T2从小到大排序,当决策当前建筑修或不修时,若当前花费时间 + T1 <= T2,则修,否则判断T1是否小于之前修的 T1最大的建筑,若小于,则修,我们可 ...