讨论一个字符串的所有后缀的最长公共前缀(不同后缀间前面相等部分)有两种情况:
(1)相邻排名的后缀间的lcp(pos[i],pos[i+1]).
(2)任意后缀间的lcp(pos[i],pos[j]).
构造height数组的方法已在上篇博客中提到,本篇文章主要讨论如何由height数组构造lcp,由于这个方法是我自己创造,正确性还有待指正,大家看后要是觉得有不对的地方可以给我留言。
由height数组求任两个后缀间的lcp()。因为搜索时利用二分法只需要lcp(L,M)及lcp(M,R),所以可以利用完全二叉树进行存储,叶节点为lcp(j-1,j)即所有的height值,根节点为lcp(0,n-1),父节点lcp(i,j)=min{lcp(i,k),lcp(k,j)}(k=(i+j)/2),非终叶结点有n-2个,终叶结点有n-1个,空间复发度为O(2n-3) = O(n), 将非终叶结点保存在lcp[1..n-1]中,其中lcp(i,j) = lcp[(i+j)/2], 时间复杂度为O(n).例如如下n=8的二叉树:
(1)求lcp.主程序中调用GetLcp(0,n-1)即可求出所有所需要的lcp值。采用树的搜索进行遍历,父节点取孩子中的最小者,由于左子树的高度一定低于右子树,所以遍历时只分两种情况。因为只遍历每个节点,所以时间复杂度和空间复杂度均为O(n).
/** 通过height数组求lcp(i,j) **/
void GetLcp(int i,int j){
if(i>=j-1)return ;//到达叶结点则终止
int k=(i+j)/2;
if(k==i+1&&j==k+1){ //左右孩子均已为叶结点
lcp[k]=height[k]<height[j]?height[k]:height[j];
return;
}
if(k==i+1){//左孩子已为叶结点
GetLcp(k,j);
lcp[k]=height[k]<lcp[(k+j)/2]?height[k]:lcp[(k+j)/2];
return;
}
/** i<j-1时求二叉树的内部结点 **/
GetLcp(i,k);
GetLcp(k,j);
lcp[k]=lcp[(i+k)/2]<lcp[(k+j)/2]?lcp[(i+k)/2]:lcp[(k+j)/2];
}