KMP算法复杂度证明

引言

KMP算法应该是看了一次又一次,比赛的时候字符串不是我负责,所以学到的东西又还给网上的博客了……

退役后再翻开看,看到模板,心想这不是\(O(n^2)\)的复杂度吗?

有两个循环也不能看做是\(O(n^2)​\)的,这要用到摊还分析.

模板

这里用到的模板是算竞上的

  • calc_next()
    Next[1] = 0;
    for (int i = 2, j = 0; i <= n; ++i) {
        while (j > 0 && a[i] != a[j + 1]) j = Next[j];
        if (a[i] == a[j + 1]) ++j;
        Next[i] = j;
    }
  • kmp()
   for (int i = 1, j = 0; i <= m; ++i) {
        while (j > 0 && (j == n || b[i] != a[j + 1]))j = Next[j];
        if (b[i] == a[j + 1])++j;
        f[i] = j;
    }

可以发现上下两个函数挺像的,Next[i]含义就是匹配串以\(i\)结尾的子串([1..i]的后缀)与模式串的前缀能匹配的最长长度

证明

观察发现有两个操作:

  • 匹配成功:j++,这个代价是1
  • 匹配失败: j=Next[j]还要经过while循环,这个代价未知

根据记账法,假设每个平摊代价是2,对于每个匹配成功的操作,其中1元用来j++,另1元就存起来,给后面匹配失败时用:

而当失配的时候,就会用到银行存款,最坏的情况当然就是用光了所有存款,但可以发现每个匹配的操作分配两个时间代价是完全足够的

换句话说,你使用存款肯定得要求银行有存款,而每次j++操作都会存1元,在当前j前面必然每个位置都是有大于等于1的存款

所以复杂度就是j++次数的两倍,也就是匹配串的长度 \(2n\)

根据平摊分析要求\(\check c_i \ge c_i\),平摊代价设置为\(2\)是完全满足的

综上所述:KMP算法两个函数的总体运算次数为\(2n+2m\),复杂度是\(O(n+m)\)

总结

也不知道这样分析对不对,如果只是感性理解的话足够了.

也有势能法的做法,但是这样的话就要定义势能函数,我觉得记账法还是好理解一点.

全部评论

相关推荐

面试官全程关摄像头1.自我介绍一下2.React和Vue哪个更熟悉一点3.你在之前那段实习经历中有没有什么技术性的突破(我只是实习了44天工作28天,我把我能说的都说了)4.你封装的哪个表单组件支不支持动态传值5.自己在实习阶段Vue3项目封装过hook吗6.hook有什么作用7.Vue2和Vue3的响应式区别(我说一个是proxy是拦截所有的底层操作,Object.defineProperty本身就是一个底层操作,有些东西拦截不了,比如数组的一些操作还有等等,面试官就说实在要拦截能不能拦截????我心想肯定不行呀,他的底层机制就不允许吧)8.pinia和vuex的区别(这个回答不出来是我太久没用了)9.pinia和zustand的区别,怎么选(直接给我干懵了)(我说react能用pinia吗&nbsp;&nbsp;他说要用的话也可以)10.渲染一万条数据,怎么解决页面卡顿问题(我说分页、监听滚轮动态加载,纯数据展示好像还可以用canvas画)(估计是没说虚拟表单,感觉不满意)11.type和interface的区别12.ts的泛型有哪些作用(我就说了一个结构相同但是类型不同的时候可以用,比如请求响应的接口,每次的data不同,这里能用一个泛型,他问我还有什么)13.你项目用的是React,如果让你再写一遍你会选择什么14.pnpm、npm、yarn的区别15.dependencies和devdependencies的区别总而言之太久没面试了,上一段实习的面试js问了很多。结果这次js一点没问,网络方面也没考,表现得很一般,但是知道自己的问题了&nbsp;&nbsp;好好准备,等待明天的影石360和周四的腾讯了&nbsp;&nbsp;加油!!!
解zj:大三的第一段面试居然是这样的结局
查看15道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务