基于对称性 理解kmp中 j=next[j]

leetcode周赛181题1392最长快乐前缀
看到kmp解法后一直无法理解j=next[j],想了一天后终于通过对称性想明白了。
1392. 最长快乐前缀 https://leetcode-cn.com/problems/longest-happy-prefix/

class Solution:
    def longestPrefix(self, s: str) -> str:
        n = len(s)
        next = [-1] * n
        for i in range(1,n):
            j=next[i-1]
            while j>-1 and s[j+1]!=s[i]:
                j = next[j]###为什么? 其实是一个分解为更小的对称结构的过程
            if s[j+1] == s[i]:
                next[i] = j+1
        return s[:next[-1]+1] 

举两个例子
情况1:j>-1 and s[j+1]!=s[i]出现一次:
abab c abab a
判断k之前的字符串的最长对称前后缀
即对abab c abab a 进行判断
s[i] = ‘a’
对于i 前的部分 abab c abab
最长相同前后缀为’abab’,那么这两个前后缀是对称的的两块
即此时j = 4
对于i 前的部分,j+1=5

while j>-1 and s[j+1]!=s[i]:

s[j+1] = s[5] =‘c’ != s[i]=‘a’:

所以我们找不出ababc ababa 长度为5的对称前后缀
那么利用对称性
我们去看第一个大对称块abab中更小的对称块前缀是ab,即next[4] = 2
–>这个对称性可以延续到第二个大对称块的小对称块后缀也是ab
abab c abab a
这时,j=next[j] = next[4] = 2我们来判断这个小块+后一个字符 = s[2+1] 是否等于s[i]
即ababc ababa 与‘a’是否相等,这里相等,所以next[i] = j+1 = 2+1 = 3
即我们得到最终总的最长相同前后缀长度=3

情况2:j>-1 and s[j+1]!=s[i]一直出现,即无论取再小的对称块后的一位都匹配不上s[i]:
abab c abab t
同样的流程走一遍
abab c abab t
这时匹配对象为abab c abab t
‘t’ ! = ‘c’:继续找更小的对称块
abab c abab t
这时匹配对象为abab c abab t
‘t’ ! = ‘a’:继续找更小的对称块
abab c abab,首尾不等,所以已经没有更小的对称块了,所以j = next[j]一直递归到-1结束
即我们得到最终总的最长相同前后缀长度=0

总结:
kmp中j=next(j)就是拆解为对称的两块因为对称性可以延续从而保证首尾两个最小的块依然对称
[()a…()] b…[()…()] a
第一次拆解->(()a…()) b !=(()…()) a
第二次拆解->()a == ()a

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这是关于字符串匹配算法KMP的问题,k=next[j]是计算next数组的公式。next[j]表示在字符串P的第j个字符之前的字符串,存在长度最长的相等前后缀的长度。计算next[j]需要用到已经计算出来的next数组的值,具体过程可以参考KMP算法的实现。 ### 回答2: 在字符串匹配算法KMP算法是一种高效的算法,它利用了模式串的部分匹配信息,避免了无效的比较,提高了匹配的效率。在KMP算法,我们需要求解的是一个"next"数组,用于在模式串与主串匹配过程,当出现字符不匹配时,快速确定下一个比较点的位置。 在KMP算法,K值是通过计算模式串前缀与后缀的最长公共前缀长度来确定的。具体而言,设模式串为pattern,已知前j个字符的next数组值,即next[1]、next[2]、...、next[j],那么要计算next[j+1]的值,有以下的思路: 1. 首先,当pattern[j]与pattern[next[j]]相等时,说明pattern[j+1]与pattern[next[j]+1]也相等,即最长公共前缀长度加1。 2. 当pattern[j]与pattern[next[j]]不相等时,我们可以继续缩小最长公共前缀的长度,即将j更新为next[j],再次尝试与pattern[j+1]进行匹配。 3. 直到找到一个与pattern[j+1]匹配的位置,或者已经到达最长的前缀长度0时停止。 最终,找到的最长公共前缀长度即为next[j+1]的值。 因此,K=next[j]的含义是:当模式串pattern[j]与主串不匹配时,在模式串应该回溯到next[j]的位置,继续与主串进行下一轮的匹配。这样可以减少比较的次数,提高匹配的效率。 总而言之,K=next[j]的作用是指示在字符串匹配当遇到不匹配时,模式串下一次比较的起始位置。这样可以避免不必要的比较,提高算法的效率。 ### 回答3: k = next[j] 是为了在KMP算法,用来在匹配失败时快速确定下一次需要比较的位置。 在KMP算法,我们需要在文本串找到与模式串相匹配的子串。当某一位字符匹配失败时,传统的匹配算法会重新从当前位置的下一位重新开始匹配,这就造成了不必要的重复比较。 KMP算法的next数组,记录了模式串前缀与后缀的最长相等前后缀长度。这个信息可以帮助我们在匹配失败时,快速跳过已经比较过的部分,直接从最长公共前后缀的下一位开始。 假设我们当前比较的位置是i,对应的模式串位置是j,此时匹配失败。根据next数组可知,j = next[j],也就是说我们将从模式串的最长公共前后缀的下一位j = next[j]开始继续比较,而不用重新开始。 通过这样的跳转,可以大大减少比较的次数,提高匹配的效率。 举个例子来说明: 假设模式串为 "ABCDABD",next数组为 [0,0,0,0,1,2,0],文本串为 "ABCD ABCDABCDABD"。 当匹配到第12位时,即 "ABCD ABCDABD" 的 "D" 与模式串的 "C" 不匹配。此时我们可以根据next数组知道,下一次需要比较的模式串位置是j=2,即 "B"。 这样我们就可以快速跳过前面的 "AB" 部分,而不用从头重新开始比较。可以看出,通过next数组的帮助,我们能够更高效地进行模式匹配。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值