• KMP && exkmp && manacher


    1.KMP

    kmp是用来字符串匹配的一种算法,核心是next数组的使用,如果暴力去匹配,假设a[n], b[m], 那么复杂度为o(nm)的,但其实可以通过next数组(前缀与后缀的最大匹配值)来降低到o(n +m), 意思就是比如a[i + 1] != b[j + 1], 那么暴力来说,就只在从0重新开始匹配,但是其实不是每一次都返回到0的,只要返回到前缀的后一个等于b[j+1], 因为b[n ~ j] 和b[0 ~ n -1]是一样的,若b[j + 1]不匹配则,返回到b[n]看看b[n + 1]是否匹配。也就是next数组的含义。

                for (int i = 2, j = 0; i <= n; i ++)
                {
                while(j && a[i] != a[j + 1]) j = ne[j];
                if(a[i] == a[j + 1]) j ++;
                ne[i] = j;
                }
                
        
            for (int i = 1, j = 0; i <= m; i ++)
            {
                while(j && b[i] != a[j + 1])    j = ne[j];
                if(b[i] == a[j + 1])    j++;
                if(j == n)
                {
                    
                }
            }
    View Code

    Kmp有一个循环节,就是周期通过len - next[len]求得。

    2.EXKMP

    exkmp是kmp的拓展,用来判断s1[k...n]与s2[0...m]的前缀最大匹配度,使用ne数组和ex数组,分别保存的是s2[k...]与s2[0...m]的前缀最大匹配度,ex是s1[k...n]与s2[0....m]的前缀最大匹配度,再用po和j代表匹配最大的起点和终点,第一种其中匹配的ne[i-po] + i小于ne[po]+po说明匹配的还在最大段里,那么ne[i-po]等于ne[i],若大于等于了则要手动匹配过去j = ne[po] + po - i与i + j开始匹配,然后更新po。然后同样的方法得到ex数组。

    void getne(char *str)
    {
        int i = 0, j, po, len = strlen(str);
        ne[0] = len;
        while(str[i] == str[i + 1] && i + 1 < len)
            i++;
        ne[1] = i;
        po = 1;
        for (int i = 2; i < len; i ++)
        {
            if(ne[i - po] + i < ne[po] + po)
                ne[i] = ne[i - po];
            else
            {
                j = ne[po] + po - i;
                if(j == -1) j = 0;
                while(i + j < len && str[j] == str[i + j])
                j ++;
                ne[i] = j;
                po = i;
            }
        }
    }
    
    void exkmp(char *s1, char *s2)
    {
        int i = 0, j, po, len = strlen(s1), l2 = strlen(s2);
        getne(s2);
        while(s1[i] == s2[i] && i < len && i < l2)
        i ++;
        ex[0] = i;
        po = 0;
        for (int i = 1; i < len; i ++)
        {
            if(ne[i - po] + i < ex[po] + po)
            {
                ex[i] = ne[i - po];
            }
            else
            {
                j = ex[po] + po - i;
                if(j == -1) j = 0;
                while(i + j < len && j < l2 && s1[j + i] == s2[j])
                j ++;
                ex[i] = j;
                po = i;
            }
        }
    }
    View Code

    3.MANACHER

    用来判断一个字符中的最大回文串,利用回文串的性质,降低复杂度。用p[i]表示以s[i]为中心的最大回文串半径,p[i] - 1就是原来的原串匹配长度。那么问题就变成了求p[i],首先字符有奇偶,偶数不好操作,在每个字符中间加入‘#’,s[0]加入‘@’(防止越界)。

    同意用id来表示最大回文串的中心,p[id] + id就是要匹配的字符。那么产生的那种情况,一种是mx大于i 那么根据回文串就会有一个对称的点 2 * id - i 比较p[2 * id ] - i 与mx - i的大小,然后手动匹配,若mx小于等于i,那么就要手动更新i + p[i] 和i - p[i]。再更新id和mx。

            int len = strlen(str);
            for (int i = len; i >= 0; i --)
            {
                str[(i << 1) + 1] = '#';
                str[(i << 1) + 2] = str[i];
            }
            str[0] = '@';
            len = len * 2 + 2;
            manacher(str, len);
    
    void manacher(char *s, int len)
    {
        p[0] = 1;
        int mx = 0, id = 0;
        for (int i = 1; i < len; i ++)
        {
        
            p[i] = mx > i ? min(mx - i, p[id * 2 - i]) : 1;
            while(s[i + p[i]] == s[i - p[i]])
                p[i] ++;
            if(i + p[i] > id + p[id])
            {
                id = i;
                mx = i + p[i];
            }
        }
    }
    View Code
  • 相关阅读:
    丁丁又病了
    领导之所以是领导
    丁丁的进步
    最近比较烦
    批量更新数据表
    转帖:《EnterLib PIAB深入剖析》系列博文汇总
    XML DOM介绍
    转大白话系列之C#委托与事件讲解大结局
    using
    jQuery工作原理解析以及源代码示例
  • 原文地址:https://www.cnblogs.com/xwdzuishuai/p/11246780.html
Copyright © 2020-2023  润新知