[LeetCode]最长回文子串再回顾

题目描述:

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。

示例 2:
输入: “cbbd”
输出: “bb”

通过回顾最长回文子串这个题目,加深了对动态规划的理解。原来的理解:以为动态规划就是用来求最长公共子串的,这个理解太窄了。动态规划的核心还是递归,或者叫分治策略,这个方法有两个关键点:
1.自底向上的递归。
2.存储已经算好的数据,用于计算后续数据。

动态规划的含义,很难从字面上理解清楚。最好就是类比到递归,分清楚二者的区别。递归通常是自顶向下的处理问题,同时不做存储,需要的时候现场计算。因此,递归的时间复杂度通常会高于动态规划。

具体到本题,怎么用动态规划解决?
1.先计算长度为1、2的子串状态(是否为回文字符串),计算公式如下:
P(i,i)=True
P(i,i+1)=(s(i)==s(i+1))
2.用矩阵存储好上述状态。
3.继续依次计算长度为3、4……、len(s)的子串状态,计算公式如下:
P(i,j)=(P(i+1,j-1) and s(i)==s(j))
其中P(i,j)表示从索引i到j的字符串状态。
4.计算过程中记录好max_l和start_l,字符串的最大长度和起点。

这个过程中,明显的包含动态规划的两个关键点:一是自底向上的递归,先算长度为1、2的子串状态,并以此为基础计算更长子串的状态。二是存储已经算好的子串状态。

代码如下:

# -*- coding: utf-8 -*-
import numpy as np

# 字符串
s="efabcecba"
# 定义矩阵
dp=np.zeros((len(s),len(s)))

# 动态规划:计算长度为1,2的子串状态
for i in range(len(s)):
    dp[i][i]=True
    if i<len(s)-1 and s[i]==s[i+1]:
        dp[i][i+1]=True

print dp

max_l,start_l=0,0
# 计算长度为3以上的子串状态,i是起点,l是首尾字符之间的距离
for l in range(2,len(s)):
    for i in range(len(s)-l):
        dp[i][i+l]=(dp[i+1][i+l-1] and s[i]==s[i+l])
        if l>max_l and dp[i][i+l]==True:
            max_l=l
            start_l=i

print dp

print max_l,start_l,s[start_l:start_l+max_l+1]



你可能感兴趣的:(Python)