【字符串】总结

python中字符串的元素是不可变的!
如果需要对字符串进行修改,需要先变成列表再修改,最后再变回字符串。

# string->list
s = list(s)
s = s.split()

# list-> string
return ''.join(s)

KMP算法

解决一个字符串(文本串)是否包含另一个字符串(模式串)的问题,采用暴力算法时间复杂度为O(m*n),采用KMP算法则为O(m+n)
具体来说需要先根据模式串构造一个前缀表next数组,用于讲模式串回退到与文本串有相同元素的位置,而不需要从头开始检测。

前缀表next

注意这里的对称不是指 aba 这种中心对称,而是abab这种两个块相同的对称。参考链接: KMP算法的前缀next数组最通俗的解释,如果看不懂我也没辙了
当遍历到模式串中某个元素时,需要看看他之前是否存在相同的字符(块)
以下面这个字符串为例介绍一下前缀表的作用以及如何构造,“abcdabcab”
next初始为len(s)*0的数组。
前缀指的是包含首字符但不包含尾字符的所有子串,因此我们从“ab”开始依次遍历各个子串。

  1. j=0,next[i]=0; i=1,遍历到b时,由于与a不同,所以对称度是0,next[i]=0;
  2. i=2,遍历到c时,由于与a不同,所以对称度是0,next[i]=0;
  3. i=3,遍历到d时,由于与a不同,所以对称度是0,next[i]=0;
  4. i=4,遍历到a时,与a相同,所以对称度+1,next[i]=1,j+1(因为下标从0开始,所以j既可以表示对称度,也可以表示最大相同前缀的下标);
  5. i=5,遍历到b时,与ab相同,所以对称度在上一步基础上+1,next[i]=2,j+1;
  6. i=6,遍历到c时,与abc相同,所以对称度在上一步基础上+1,next[i]=3,j+1;
  7. i=7,遍历到a时,{与d不同,无法继承之前的对称度,所以回到next[j-1]的位置},直到遇到与下标为i的元素相同的字符或者j=0,遇到了下标为0的a,相同,所以对称度是1,next[i]=1,j+1;
  8. i=8,遍历到b时,与ab相同,所以对称度在上一步基础上+1,next[i]=2;
  9. i=9,遍历到c时,与abc相同,所以对称度在上一步基础上+1,next[i]=3,j+1;
  10. i=10,遍历到a,与第七步类似;
  11. i=10,遍历到b,与第八步类似;
    最终生成的前缀表next为[0, 0, 0, 0, 1, 2, 3, 1, 2]
def getNext(needle):
	n = len(needle)
    next = [0] * len(needle)
    j = 0
    for i in range(1,n):
        while j>0 and needle[i]!=needle[j]:
            j = next[j-1]
        if needle[i] == needle[j]:
            j += 1
        next[i] = j
    return next

文本串与模式串匹配

依次遍历文本串的每个元素(下标为i)
同时j指针遍历模式串的每个元素。
当文本串的元素与模式串的元素相同,j+1;
如果不同,就返回模式串的前一个元素对应的前缀表next指向的元素,即next[j-1],直到j=0或者遇到与文本串相同的元素。
以下面的例子为例:
文本串:“abcdabcdabcab”
模式串:“abcdabcab”
next:[0, 0, 0, 0, 1, 2, 3, 1, 2]
当文本串遍历到i=7,元素为d时,模式串遍历到j=7,元素为a,元素不同,所以模式串指针j回退到next[j-1],即j=3,元素为d的地方,此时成功匹配。继续匹配,发现后面的元素都能一一匹配上,因此在文本串中找到了模式串。
如果按照暴力方法,从i=0的子串匹配失败后,就继续从i=1的子串开始匹配,依次类推,效率很差。这就体现了KMP算法的优点,可以记录前面出现的重复的字符,即最长相等前缀。
carl哥说:式串与前缀表对应位置的数字表示的就是:下标i之前(包括i)的字符串中,有多大长度的相同前缀后缀

匹配部分代码

j = 0
n = len(haystack)
subn = len(needle)
hash = getNext(needle)
print(hash)
for i in range(n):
    while j>0 and haystack[i]!=needle[j]:
        j = hash[j-1]
    if haystack[i]==needle[j]:
        j += 1
        if j == subn:
            return i-j+1
return -1

发现匹配过程与构造next数组的过程几乎一模一样,个人感觉构造next数组的过程就像是一个匹配过程,是needle[1:n]与needle[0:n-1]的匹配

本题链接:28. 找出字符串中第一个匹配项的下标
此外,构造的next数组也可以用于寻找字符串的重复子串问题:459. 重复的子字符串

猜你喜欢

转载自blog.csdn.net/LoveJSH/article/details/129433037