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