左 . 进阶算法---KMP算法/BFPRT算法/窗口(双端队列)
KMP算法:
常规想法:
一个个匹配 时间复杂度太高
总结: 我们发现 每次匹配前面的并没有给后面一些指导信息
Note: 子串 和子序列不一样 前者是连续的 后者可以是不连续的 注意区分
详细解释如下:
KMP算法思路:
1 现根据match生成最大前后缀匹配长度数组 :
2 从str[i]字符出发---匹配到j位置上发现开始出现不匹配:
3 下一次match 数组往右滑动, 滑动大小为match当前字符的最大前后缀匹配长度,再让str[j]与match[k]进行下一次匹配~
4 注意为什么加快,主要是str[i]--c前那段不用考虑,因为肯定不能匹配~
若有匹配 则出现更大的前后缀匹配长度 ,与最初nextArr[] 定义违背。
代码:
关于nextArr数组的求解:
代码:
讨论计算复杂度:
相关题目:
1 .给定一个字符串 如何加最短的字符(只能在原始串的后面进行添加)使其构成一个长的字符串且包含两个原始字符串~
思路:其实就是最大前后缀长度数组~ e.g. abcabc ---->abcabcabc 最少增加3个
多求一位nextArr 可以看出之前4个复用 所以再添一位就好~
总结: 在KMP中nextArr数组基础上 多求一位终止位 将不是的补上即可
2. 给定两个树 判断树2是否为树1的子树 是则返回true
思路: 把一棵树序列化为字符串(字符数组) 如果str2是str1的子串 则T2也是T1的子树。
3 判断一个大字符串是否由一个小字符串重复得到~
转换为 一个前缀和后缀相差整数倍的问题
Manacher算法(先待定):
常规思路:
1 总是从中间那个字符出发--向两边开始扩展--观察回文
但是奇数位数字完全可以 偶数位数字不可以 会出错
2 经过规律发现 无论是哪种情况 总是 最大值/2 即为最大回文串长度
前提是 要处理字符串形式 加入特殊字符占位 #进行填充
这种方法是 暴力法 时间复杂度为O(n2)-----而Manacher算法可以降到O(n)
BFPRT算法:
、
这个算法其实就是用来解决 : 求解最小/最大的k个数问题:
常规的做法 就是 平均时间复杂度为O(n)的 partition函数的应用 ---缺点:是概率式的
此算法优点是 确定性的。
大概思路:
将整个数组以5个数字一组划分 分别进行组内排序 时间复杂度为O(1) ---分为N/5组---则总共时间复杂度为O(N)
3) 把每个组内的中位数拿出来构成一个新数组 若为偶数 则拿其上中位数即可
4)继续调用 该函数 传入刚才的中位数数组 和 数组长度的一半 (继续求中位数)
5)将4)返回的值与 k进行对比 左右中 ---
例子:
每一步的时间复杂度为:
优点 :我们选择的基准一定将数组划分为 一定规模的子部分
由上图我们可以看到: 最中间的中位数--- 右边比它大的至少有N/10 * 3 个(每个组又有两个大于该组中位数的数字)
右边比它小的最多有N/10 * 7
---- 同理左边也是~
如下例子: 7为中位数 ----比它大的至少有 8 9 12 13 14 这几个数
最终统计时间复杂度为:
重点掌握思路 可以面试的时候告诉面试官~~
代码:
注意: 此时的partition和常规的partition函数不太一样 多了一个我们定义的基准划分值
且以此基准值划分 比它小的在左边 比它大的在右边 和它相等的在中间并将相等的左右边界存放在一个数组中
窗口:
什么是窗口:
就是一个数组------有L和R指针 当有数字进入时R向右移动 当有数字删除时则L向右移动 且L 和R 不会回退~
思路: 双端队列(链表)
可以从头 尾入 可以从尾 头出
规则: L< R 且 L,R 永远不回退~
分析逻辑为: 双端队列按照从大到小的顺序 放入元素
(R增加) 头部始终存放的是当前最大的元素--- 如果即将进入的元素比上一个进入的元素小 则从尾部进入 连接在后面
------否则 尾部一直弹出(包含相等情况,因为晚过期) 直到为 即将要放入的元素 找到合适的位置
(L增加) ---L向右移---(index下标一定得保留)则需要检查当前头部元素index是否过期 若过期则需要从头部进行弹出
具体应用:
生成窗口最大值数组:
生成窗口最大值数组:
代码:
最大值-最小值<=num的子数组数量:
最简单思路: 暴力求解 两个for 依次遍历
分析时间复杂度: o(N3) n的3次方
最优解思路:
1 如果有一个子数组L-R已经符合要求--则其中内部的子数组一定也符合要求----因为L max-- min++
2 如果已经不达标 则往两边扩也肯定不达标
3 总计规律: 就是L一直往右走 不回退 R也跟着往右扩大范围
代码: