字符串匹配 之 拓展 KMP算法(Z算法)

灵神代码模版

  • 区别与KMP算法

    • KMP算法可用于求解在线性时间复杂度0(n)内求解模式串p在主串s中匹配的未知
    • 当然,由于在KMP算法中,预处理求解出了next数组,也就是可以求解出字符串p的真后缀与真前缀的最大公共前缀LCPnext[i]表示字符串p[0] 到 p[i] 的真前缀和真后缀的LCP
  • 拓展KMP算法(Z函数):

    • 用于求解主串s的后缀与模式串p的LCP
    • 当然,预处理过程中的z[i]可用于求解字符串p[i:] 与字符串p的LCP

下面给出求解Z数组的python 代码

# 计算并返回 z 数组,其中 z[i] = |LCP(s[i:], s)|
def calc_z(s: str) -> List[int]:
    n = len(s)
    z = [0] * n
    # box_l和box_r维护的是一个区间,
    # 也就是s[box_l:box_r+1]与s[box_r]匹配
    box_l = box_r = 0
    for i in range(1, n):
    	# 当i在区间内,就可以利用先前的信息
        if i <= box_r:
        	# 这个z[i-box_l] 十分巧妙
            z[i] = min(z[i - box_l], box_r - i + 1)
        while i + z[i] < n and s[z[i]] == s[i + z[i]]:
            box_l, box_r = i, i + z[i]
            z[i] += 1
    z[0] = n
    return z
  • 重点分析为什么落在区间的时候,有z[i]=min(z[i - box_l],box_r - i + 1)
    • 首先,对于i-box_l,是左边的情况,我们得时刻记得s[box_l:box_r+1]与s[box_r]匹配,所以,我们更加关注从s[i]开始的情况,也就是s[box_l]开始的情况,所以可以直接借鉴
    • 对于box_r-i+1,是对于区间提供信息的长度限制,不能超过box_r-i+1,因为超过这个范围的信息没有记录

习题

2223.构造字符串的总得分和

2223.构造字符串的总得分和

在这里插入图片描述
在这里插入图片描述

  • 思路分析:拓展kmp算法模版题目
class Solution:
    def sumScores(self, s: str) -> int:
        # 拓展kmp算法的模版题目

        n = len(s)
        z = [0]*n 
        box_l,box_r =0,0
        for i in range(1,n):
            if i <= box_r:
                z[i] = min(z[i-box_l],box_r-i+1)
            while i + z[i] < n and s[z[i]] == s[i + z[i]]:
                box_l,box_r = i,i+z[i]
                z[i] += 1
        z[0] = n 

        return sum(z)

3031.将单词恢复初始状态所需的最短时间 II

3031.将单词恢复初始状态所需的最短时间 II

在这里插入图片描述
在这里插入图片描述

灵神题解

  • 思路分析:我们需要考虑原始序列,与当前位置的后缀的最长公共前缀的长度关系,如果z[i]>=n-i,并且i%k==0,就说明可以通过i//k次就可以通过恢复原型,当然,如果遇到无法恢复的情况,我们至多 ⌈ n k ⌉ \left\lceil\frac{n}{k}\right\rceil kn次即可恢复
class Solution:
    def minimumTimeToInitialState(self, word: str, k: int) -> int:
        # 拓展kmp算法问题
        # 反正就是查看z[k]是否等于k ,一直找
        n = len(word)
        z = [0]*n 
        box_l,box_r = 0,0
        for i in range(1,n):
            if i <= box_r:
                z[i] = min(z[i-box_l],box_r-i+1)
            while i + z[i] < n and word[z[i]] == word[i+z[i]]:
                box_l,box_r = i,i+z[i]
                z[i] += 1
            if i % k == 0 and z[i] >= n - i:
                return i // k
        # 如果复原不了,那也只是 n // k 的向上取整
        return  (n-1) // k + 1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值