• 字符串学习笔记


    字符串学习笔记

    哈希

    最基础的字符串算法, 规定一个质数(p), 将字符串转换为一个(p)进制的数

    字符串最小循环表示法

    咕咕咕

    KMP

    定义需要被匹配的串叫做

    我们知道暴力算法是在每一个位置开始匹配, 匹配不成功时位置++

    这样的算法最好时间复杂度是(O(原串长度)), 最坏时间复杂度是(O(原串长度*匹配串长度))

    考虑对暴力算法的优化

    我们知道对于一个字符串, 若它在当前位置匹配不成功, 并且出现了这样一个情况

    1.png

    这个红色和蓝色是满足相等的条件下的, 最长的前缀和后缀, 若此时指针在蓝色右边, 我们可以直接将指针移至红色端点右边, 继续匹配

    对于一个字符串(S), 它的长度为(n)

    我们设(nxt[i])为满足对于(S)的一个字串(S[1 - i]), 有(S[1 - nxt[i]]) = (S[(i - nxt[i] + 1) - i])这一条件的最大的下标

    那么我们对于字符串匹配就有了这样的算法

    	for(int i = 1; i <= n; i++)
    	{
    		while(pos && s2[pos + 1] != s1[i])
    			pos = nxt[pos];//无法匹配时跳到nxt处继续匹配
    		if(s2[pos + 1] == s1[i]) pos++;//若相等指针后移
    		if(pos == m)//整个字符串完成匹配
    		{
    			printf("%d
    ", i - pos + 1);
    			pos = nxt[pos]; //重新开始匹配
    		}
    	}
    

    现在所求就变成了怎么求nxt数组

    我们考虑这样一个过程

    (S[1 - (i - 1)])(S[1 - i])匹配, 当原串的指针超出原串范围时, 此时匹配串的指针即为(nxt[i])

    因为此时(S[1 - nxt[i]])(S[(i - nxt[i] + 1) - i])相同

    若此时(S[1 - nxt[i]])不为最长子串, 那么在上一次跳(nxt)时是不会跳到当前位置的, 而会跳到最长子串所在的位置

    感性理解一波

    对于每次新加上一个字母, 我们没有必要去重新匹配, 可以直接在原来的基础上继续匹配, 具体原因感性理解一下吧, 在两个不匹配的字符串的后面加上不同的字母对匹配是没有影响的

    于是有

    	for(int i = 2; i <= m; i++)
    	{
    		while(pos && s2[pos + 1] != s2[i])
    			pos = nxt[pos];
    		if(s2[pos + 1] == s2[i]) pos++;
    		nxt[i] = pos; 
    	}
    

    我在学习的时候发现了一个问题, 是这样的, 有没有可能在从(i)跳到(nxt[i])的过程中, 跳过了一些可能对答案造成贡献的点, 也就是:

    2.png

    红点是(i), 蓝点是(nxt[i]), 紫串是(S[1 - nxt[i]]), 绿串是同时存在于前缀和后缀的一个比紫串更加长的子串

    显然矛盾, 如果有这种情况, 那么(nxt[i])就是绿色的左边了

    康康别人的博客吧, 这个我自己能看懂就行

    ExKMP

    咕咕咕

    后缀数组

    咕咕咕

    后缀自动机

    咕咕咕

    回文自动机

    咕咕咕

    AC自动机

    咕咕咕

    KMP自动机

    咕咕咕

    Manacher

    咕咕咕

  • 相关阅读:
    一个短信验证码倒计时插件
    记一次图片优化经历
    前端开发中两种常见的图片加载方式
    《javascript面向对象精要》读书笔记
    less hack 兼容
    第一次项目总结
    你总说毕业遥遥无期,可转眼就各奔东西
    【翻译】理念:无冲突的扩展本地DOM原型
    【翻译】jQuery是有害的
    202002280156-《统治世界的10种算法(摘自极客大学堂)》
  • 原文地址:https://www.cnblogs.com/ztlztl/p/11627623.html
Copyright © 2020-2023  润新知