zoukankan      html  css  js  c++  java
  • 学点字符串匹配——zbox

      先来规定一些符号,S表示一个字符串,|S|表示字符串的长度,没有特殊说明n表示匹配串的长度,m表示模式串的长度。prefix(i)表示S的后缀S[i...n]。

      zbox算法只是对一个字符串S求出一个数组Zbox[]。Zbox[i]表示的是prefix[i]和字符串S的最长公共前缀的长度。即zbox算法的目的是初始化所有字符串后缀对与原串的最长公共前缀长度。

      先来看看通过Zbox[]数组如何进行精确匹配。匹配串记为S,模式串记为P。要用一个数组把S和P关联起来,一个常用的方法是把S和P连接。这里把P放在前面得到新串T = P+S。现在对新串进行zbox的过程求出Zbox[]。根据定义可知S串如果从i处匹配上了P串,则Zbox[i + m] = m。于是可以遍历T串的[m, n + m - 1],寻找匹配结果。

      zbox的快速求Zbox[]的方法是在暴力的基础上对于可以确认的以前匹配过的字符直接跳过。算法的关键在于在比较中不断更新区间[l,r](zBox[l] = r - l + 1,这是通过计算prefix(l)更新的),使以后要计算的zBox[i]尽可能在[l, r]内。

    现在考虑怎么通过[l, r]降低复杂度:

    1. T[l, r] = T[0, r - l + 1];
    2. i在[l, r]间;
    3. 由1,2:T[i, r] = t[i - l. r - l + 1];
    4. 由3:
      • zBox[i] = zBox[i - l], 当i+zBox[i - l] < r, 因为i+zBox[i - l] + 1不会再匹配了
      • zBox[i] = r - l + 1 + 暴力向后比较得到的值, 当i+zBox[i - l] >= r, 因为只能保证T[i, r] = t[i - l. r - l + 1],后面只能暴力计算不能根据prefix(i - l)(都不相等了)

    上代码~

     1 unsigned int * zbox(char * str)
     2 {
     3     int idx = 0;
     4     int len = strlen(str);
     5     unsigned int *zBox = (unsigned int *)malloc(len * sizeof(unsigned int));
     6     int l = 0, r = 0;
     7 
     8     if(zBox == NULL) return NULL;
     9 
    10     zBox[0] = len;
    11     for(idx = 1; idx < len; ++idx)
    12     {  //这里的l必然小于idx,因为l总是等于之前的idx
    13         if(idx > r)//现在正在计算的后缀不在已匹配字符段内,必须从头开始比较
    14         {
    15             l = r = idx;
    16             while(r < len && str[r - l] == str[r]) ++r;
    17             zBox[idx] = r - l, --r;
    18         }
    19         else //现在正在计算的后缀在已匹配字符段内,可以跳过某些字符
    20         {
    21             //这里还分两种情况,超界和未超界
    22             int k = idx - l;
    23             if(zBox[k] < r - idx + 1) zBox[idx] = zBox[k]; //未超界,当前最大ZBOX值求出,直接赋值
    24             else
    25             {
    26                 //超界,需要跳过一些字符继续比较。
    27                 l = idx;
    28                 while(r < len && str[r - l] == str[r]) ++r;
    29                 zBox[idx] = r - l, --r;
    30             }
    31         }
    32     }
    33     return zBox;
    34 }

      从这个代码可以看出r是递增不减的且r最大值是n - 1。所以均摊到外层每个循环里,while循环平均进行了1次,因此zbox复杂度为O(n)。

  • 相关阅读:
    POJ 2756 Autumn is a Genius 大数加减法
    RoboGuice注入框架简单应用
    Android 从相冊获取近期拍摄的多张照片(获取相机拍照所存储的照片)
    不可不知的DIP、IoC、DI以及IoC容器
    Codeforces Round #156 (Div. 2)---A. Greg&#39;s Workout
    zend framework将zip格式的压缩文件导入并解压到指定文件
    TreeSet排序
    Bee Framework_百度百科
    duck
    anglehack参赛总结
  • 原文地址:https://www.cnblogs.com/ACystalMoon/p/2840892.html
Copyright © 2011-2022 走看看