马拉车(manacher),KMP

本文深入探讨了Manacher算法和KMP算法的实现细节。Manacher算法用于寻找字符串中最长的回文子串,通过在字符串中插入特殊字符以统一处理奇偶回文情况,再利用回文特性快速求解。KMP算法则是一种高效的字符串匹配算法,通过预处理模式串的next数组来避免重复比较,提高搜索效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

manacher:

class Solution:
    '''这里面是利用manacher进一步做从后面添加最少的字串使其成为回文串,leetcode214T是在前面'''
    def longestPalindrome(self, s: str) -> str:
        # 加进去 '#' 使其奇偶数都行,这个函数简单
        def manacherStr(Str) -> List[str]:
            res = [0] * (len(Str) * 2 + 1)
            idx = 0
            for i in range(len(res)):
                if not i & 1:
                    res[i] = '#'
                else:
                    res[i] = Str[idx]
                    idx += 1
            return res

        def maxLcpsLength(Str) -> int:
            # 上面的生成扩展数组如果是空,会['#']
            # if not Str: return Str
            # 加上'#' 方便处理奇偶数
            charArr = manacherStr(Str)
            # pArr是回文半径数组,是对包含#的数组而言
            pArr = [0] * len(charArr)
            # C回文直径的中心,R回文右边界(回文的右边的那个char的索引,
            #               这样R-i正好包括i不包括R,正好是半径)
            C, R = -1, -1
            '''
            maxContainsEnd = -1
            '''
            # 最大半径对应的中心C
            MaxC = 0
            Max = float('-inf')
            for i in range(len(charArr)):
                if R > i:
                    # 2*C-i是i关于C的对称点索引
                    pArr[i] = min(pArr[2 * C - i], R - i)
                # 当前位置i不在R里面,暴力扩
                # 更新回文半径数组
                else:
                    pArr[i] = 1
                while i + pArr[i] < len(charArr) and i - pArr[i] > -1:
                    # 前两种会这一步都扩不动,最后一种会持续扩到不能扩为止
                    if charArr[i + pArr[i]] == charArr[i - pArr[i]]:
                        pArr[i] += 1
                    # 扩不动退出
                    else:
                        break
                # 扩不动了R移到扩不动的位置
                # 更新回文中心和回文右边界
                if i + pArr[i] > R:
                    R = i + pArr[i]
                    C = i
                    # 针对此题做的处理
                    # 更新最大回文半径对应的C,而非最大R
                    if max(Max, pArr[i]) > Max:
                        MaxC = i
                '''
                if R == len(charArr):
                    maxContainsEnd = pArr[i]
                    break
                '''
                Max = max(Max, pArr[i])
            '''
            res = [0] * (len(Str) - maxContainsEnd + 1)
            for i in range(len(res)):
                res[len(res) - 1 - i] = charArr[i * 2] + 1
            return res
            '''
            # Max是包括#的最长回文半径(包括中心点)
            # 索引加#后的数组的回文半径数组-1就是回文字串的长度
            # return Max - 1

            # C >> 1 是原数组最后的回文中心
            # 如果Max-1是偶数则c/2是下中位数(索引大的那个),若奇数则中间
            L = (MaxC >> 1) - (Max - 1 >> 1)
            # 空字符Str的Str[0:1]会返回空
            return Str[L : L + Max - 1]
        return maxLcpsLength(s)

KMP:

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        def getIndexOf(str1, str2) -> int:
            # 必须将这个写在前面
            if not str2 and not str1:
                return 0
            # str2为空,那么就默认返回0
            if not str2:
                return 0
            if not str1 or len(str1) < len(str2):
                return -1

            i1, i2 = 0, 0
            nextArray = getNextArray(str2)
            while i1 < len(str1) and i2 < len(str2):
                # 暴力找相等
                if str1[i1] == str2[i2]:
                    i1 += 1
                    i2 += 1
                # 不等,str1向前走,找到和str2开头一样的第一个char
                elif nextArray[i2] == -1:
                    i1 +=1
                # 不等,找到了和str2开头的元素,找最长前后缀匹配的长度,跳到长度索引处
                # 继续while下去
                else:
                    i2 = nextArray[i2]
            # 返回第一个相等的元素索引,即为两者差值
            return i1 - i2 if i2 == len(str2) else -1

        def getNextArray(str2) -> List[int]:
            length = len(str2)
            # 长度为1,默认0号索引的next数组为-1
            if length == 1:
                return [-1]

            nextArray = [0] * length
            nextArray[0] = -1

            # 当前位置i和跳到的位置cn(最长匹配长度的索引即那一位没有匹配上)
            i, cn = 2, 0
            while i < length:
                # 移动了一步之后,原来的位置和当前最长匹配没有配上的位置的值是否相等
                if str2[i-1] == str2[cn]:
                    # java中nextArray[i++] == ++cn相当于后面三行
                    nextArray[i] = cn + 1
                    cn += 1
                    i += 1
                # 移动一步后没有匹配上,则只是cn往前一个最长匹配没配上的位置跳,
                # i不变仍是跳的位置和i-1位置比
                elif cn > 0:
                    cn = nextArray[cn]
                # 没有配上并且前面没有最长匹配了
                # 则没有最长匹配,重新下一个位置
                else:
                    nextArray[i] = 0
                    i += 1
            return nextArray
        return getIndexOf(haystack, needle)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值