中心扩散算法-python实现

第一次写博客,有写的不好的地方希望大家多多给意见;以前都是用思维导图记笔记的,现在打算开始写写博客,分享自己学习中的一些东西。

本次内容分为以下几部分

背景

思路

暴力算法

中心扩散

结语


背景

就以一道题目入场吧——最长回文子串,题目可参考:最长回文子串_牛客题霸_牛客网

再把描述和示例截图放上:

思路

暴力算法

本人脑子愚笨,一上来只想到了暴力解决:找到所有字串,判断是否为回文子串;如果是则更新结果。用到两层循环,时间复杂度为O(n^{2}),空间复杂度为O(1),确实满足基础要求了,但是离进阶要求还差远呢。

附上一个表格形式的流程图...

当前元素ababc
需要判断的字串ababc
abbaabbc
ababababc
ababbabc
ababc

其实填充红色的那一行是没必要判断的,因为当输入非空时,最少都有一个回文子串,就是字符本身。因此需要判断的次数为

 1+2+3+...+\frac{(n-1)n}{2}

所以时间复杂度为O(n^{2})

再附上python代码

class Solution:
    def getLongestPalindrome(self , A: str) -> int:
        # write code here
        result = 1
        for i in range(len(A)):
            for j in range(len(A)):
                if A[i:j+1] == A[i:j+1][::-1]:
                    result = max(result,j+1-i)
        return result

中心扩散

接下来进入今天的主题——中心扩散算法

仔细思考我们会发现,回文字符串就是左右两边对称的字符串,如"aba","abba",根据这个思想,这时候如果我们以b为中心,向两边扩散,就能得到aba;同理对于abba,我们以bb为中心,向两边扩散,就能得到abba;

接下来我们整理出算法流程:

  • 遍历所有元素
    • 以当前元素为中心,向两边扩散,判断子串是否为回文,是则更新结果
    • 以当前元素和右边一个元素为中心,向两边扩散,判断子串是否为回文,是则更新结果

接下来附上一个表格形式的流程图...

输入"ababc"输出应该是3,即子串"aba"或"bab"
当前元素ababc
应检查元素以当前元素为中心 a  b  a  b  c 
  aba  bab  abc  
   ababc   
以当前元素和其右边元素为中心  ba  ab  bc  
  abab  babc   

同上面的暴力算法一样,填充红色的那一行是没必要进行检查的,可以看到需要判断的次数少于暴力算法,上面暴力算法对于这个示例需要检查1+2+3+4=10次,而中心扩散只需要检查2+3+4=9次。嗯……好像也没有少多少次的样子……

举个例子来说明一下为什么要检查这些子串,我们以第二个'a'为例子说明为什么要检查'bab','ababc','ab','babc'

  • 如果以当前元素'a'为中心
    • 首先我们左右各扩散一个元素,就会得到'bab',因此需要检查'bab'
    • 其次我们左右各扩散两个元素,就会得到'ababc',因此需要检查'ababc'
    • 接下来元素已经不够了,所以不需要扩散了,这里以左右两边拥有的最少元素进行扩散即可
  • 如果以当前元素和其右边元素'ab'为中心(这里选左边也行)
    • 首先我们左右各扩散零个元素,也就是检查中心本身(因为这时中心有两个元素,有可能它就是最长回文子串,这里跟上面以一个元素为中心有一点区别)
    • 其次我们左右各扩散一个元素,就会得到'babc',因此需要检查'babc'
    • 接下来我们想扩散两个元素,很明显右边已经不够扩散了,因此就没必要检查了;所以当以'ab'为中心时,右边只有一个元素'c',左右有两个元素'ba',因此我们只需扩散两次即可min(length('c'),length('ba')+1)

再附上python代码

class Solution:
    def getLongestPalindrome(self , A: str) -> int:
        # write code here
        res = 1
        le = len(A)
        if le < 2:return le
        for i in range(le-1):
            for j in range(1,min(i+1,le-i)):    # 以当前元素为中心,从1个元素开始扩展
                if A[i-j:i+j+1] == A[i-j:i+j+1][::-1]:
                    res = max(res,2*j+1)
            for j in range(min(i+1,le-i-1)):    # 以当前元素和右边元素为中心,从0个元素开始扩展
                if A[i-j:i+j+2] == A[i-j:i+j+2][::-1]:
                    res = max(res, 2*j+2)
        return res

结语

上面的暴力算法和中心扩散复杂度都达到了 O(n^{2}),好像这题用动态规划时间复杂度也要 O(n^{2}),然后看到有大佬用Manacher算法可以把时间复杂度降到O(n),有兴趣的同学可以自行搜索。

感谢大家!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值