leetcode回文子串相关编程题集合

回文,顾名思义就是段字符颠倒过来和它本身是相同的。如abcba和abba,正着读反着读都是它本身。在leetcode上关于回文的题我们将在这里进行一个总结。回文问题大多用动态规划和双指针指针来解决

判断一个字符串是不是回文子串其实只要比较s和s[::-1]就可以实现。但是问题是每次都会给你附加一些其他的。


第125题:验证回文串(简单)
leetcode回文子串相关编程题集合_第1张图片
在判断这个字符串的时候我们需要之前进行如下工序:
1.去除无关的字符,我们用re正则表达式可以轻易完成。注意的是正则结果要转换成字符串类型。
2.全体变成小写,我们用s.lower()完成。

import re
clean = re.findall('[a-zA-Z0-9]+',s)
clean = ''.join(clean)
clean = clean.lower()
print(clean)
l = len(clean)-1
if clean == clean[::-1]:
    return True
else:
    return False

  1. 验证回文字符串 Ⅱ(简单)
    leetcode回文子串相关编程题集合_第2张图片
    开始加入了其他条件:最多删除一个字符。
    我们需要想通删除一个字符意味着什么。在这道题中,删除一个字符意味着在双指针的循环中第一次遇到两边指针所指字符不同时,有一次机会跳过左侧或者右侧指针所指的、不相同的字符。
    def validPalindrome(self, s: str) -> bool:
        if s == s[::-1]:      #如果是回文直接返回
            return True
        l,r = 0,len(s)-1     #lr分别是字符串的头和尾巴
        while l

第131题分割回文串(中等)
leetcode回文子串相关编程题集合_第3张图片
本题的问题在于我们需要把一个字符串拆分成多个回文串,那么一定会有多种模式。我们能够直接想到的就是拆分成每一个字符,因为单个字符本身就是回文串。想发现带有两个字符组成的回文串的分割方式,里面或许还需要参杂着单个字符的模式——毕竟两两分割可能还真无法分割完所有的字符,例如这个aab,aa是回文而b却不是;那么三个呢?三个字符分割这个字符串里面势必又包含两个字符和单个字符的模式。我们能够感觉到这种从子问题到父问题的解决方案应该是“动态规划”或者是“递归”。那么这道题,这两种方案都可以,我们以递归为例。

def dfs(s, path, res)
这里设置的参数
s:递归处理的字符串
path:第一个for循环代表寻找以某一模式开头进行的循环。path用来保存这一模式最后获得的结果。如寻找一个递归的字符是下图绿色标注的a、b、b、a,如果寻找两个递归的字符开头的是ab但是由于ab不是回文串所以没有后续递归。
res:res记录全部的结果

黄色的bb是这样找到的:首先寻找1字符开头的模式,找到a是回文,进行递归1-1:继续找到1字符开头的模式(绿色圆圈的分支)这个模式走完后,进行递归1-2:找到2个字符开头的模式,找到bb,进行递归1-2-1:找到1个字符开头的模式,找到a。这时候因为s为空所以将path加入到res中。过程中,用path保存找到的回文串并传递下去。
leetcode回文子串相关编程题集合_第4张图片
代码如下:

s = "abba"
def dfs(s, path, res):
    if not s:
        res.append(path)
        return
    for i in range(len(s)):
        if s[:i+1] == s[i::-1]:
            dfs(s[i+1:], path+[s[:i+1]], res)    
tmp,res = [],[]
dfs(s, tmp, res)
res

  1. 最长回文子串
    给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。

显然动态规划依然是我们良好的选择,虽然有着复杂度为n的马拉车算法,还是动态规划更好理解而且具有万用性。虽然它的复杂度要高一些。
我们这样定义我们的dp数组:它表示第i个到第j个字符是否是回文子串。
这样定义之后,j一定是在i和字符串长度len之间的。我们这样更新我们的dp:
1.左上角到右下角全部置1,含义是每个字符是它自己的回文子串。
2.从外层的i从1开始进行遍历,内层的j从0开始遍历到i,意义是逐列填满所有到i行的内容,如果ij位置对应的字符是相等的,那么dp[j][i] = dp[j+1][i-1],意义是去掉两侧相等的字符是否是回文串。当然如果ij的距离为1我们直接可以判断是回文串,因为它是两个相同字符相连的样子。
3.dp更新完毕后,我们取尽量靠近右上角的dp为1的元素,因为右上角代表着j尽量小,i尽量大,如此我们可以找到最长的回文子串。
代码:

dp = [[0 for _ in range(len(s))] for _ in range(len(s))]
for i in range(len(s)):
    dp[i][i]=1
for i in range(1,len(s)):
    for j in range(i):
        if s[j]==s[i]:
            if abs(i-j)<=1:
                dp[j][i] = 1
            else:
                dp[j][i] = dp[j+1][i-1]

m_dis = 0
output = ""
for i in range(len(s)):
    for j in range(i,len(s)):
        if dp[i][j] == 1 and (abs(j-i)>m_dis or m_dis ==0):
            m_dis = abs(j-i)
            output = s[i:j+1]
      
output

用这个图来参考一下吧。
leetcode回文子串相关编程题集合_第5张图片

你可能感兴趣的:(leetcode回文子串相关编程题集合)