回文子串系列【dp】

字符串序列专题

392.判断子序列

题目大意: s = “agc” t = “ahbgdc”,请判断s是不是t的子序列

注意状态转移: 当s[i-1] == t[j-1]时,显然dp[i] [j] = dp[i-1] [j-1] +1的

但是不相等的时候,当前dp状态就应该是dp[i] [j-1]时候的状态,注意s是子串,所以只需判断j-1就行

def isSubsequence2(self, s: str, t: str) -> bool:
    # dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为dp[i][j]
    dp = [[0] * (len(t)+1) for _ in range(len(s)+1)]
    for i in range(1, len(s)+1):
        for j in range(1, len(t)+1):
            if s[i-1] == t[j-1]:
                dp[i][j] = dp[i-1][j-1] + 1
            else:
                dp[i][j] = dp[i][j-1]
    print(dp)
    if dp[-1][-1] == len(s):
        return True
    return False

115.不同的子序列

题目大意:s = " rabbbit" t = “rabbit”, 请找出s的子序列中t出现的个数

注意状态转移: 以s = “bagg” t ="bag"为例,s可以用s[0] s[1] s[3]来匹配 此时dp[i] [j] = dp[i-1] [j-1]

但是 也可以用s[0] s[1] s[2] 来匹配 此时dp[i] [j] = dp[i-1] [j] 用前者来匹配

lens = len(s)
lent = len(t)
dp = [[0 for _ in range(lent+1)] for _ in range(lens+1)]  # 以i-1为结尾的s子序列中出现以j-1为结尾的t的个数为dp[i][j]。
for i in range(lens):
    dp[i][0] = 1
for j in range(1, lent):
    dp[0][j] = 0
for i in range(1, lens+1):
    for j in range(1, lent+1):
        if s[i-1] == t[j-1]:
            dp[i][j] = dp[i-1][j-1] + dp[i-1][j]    # 自己匹配或者前者匹配
        else:
            dp[i][j] = dp[i-1][j]
return dp[-1][-1]

583.两个字符串的删除操作

题目大意:给定两个单词 word1word2 ,返回使得 word1word2 相同所需的最小步数

word1 = “sea” word2=“eat”

注意dp表示的什么

注意状态转移: 当s[i-1] == t[j-1]时,显然dp[i] [j] = dp[i-1] [j-1]的【当前不用操作】

当s[i-1] != t[j-1]时候,就应该注意到有三种方式使得它们相同,

  1. 删除s和j,此时需要dp[i-1] [j-1]的状态次数+2
  2. 删除s最后一个,此时需要dp[i-1] [j] 的次数+1
  3. 删除t最后一个,此时需要dp[i] [j-1]的次数+1

三种方式取最小即可

def minDistance(self, word1: str, word2: str) -> int:
    len1, len2 = len(word1), len(word2)
    dp = [[0 for _ in range(len2 + 1)] for _ in range(len1 + 1)]  # dp[i][j] 表示以i-1结尾和以j-1结尾需要删除的操作次数
    dp[0][0] = 0
    for i in range(1, len2 + 1):
        dp[0][i] = i
    for j in range(1, len1 + 1):
        dp[j][0] = j
    for i in range(1, len1 + 1):
        for j in range(1, len2 + 1):
            if word1[i - 1] == word2[j - 1]:
                dp[i][j] = dp[i - 1][j - 1]
            else:
                dp[i][j] = min(dp[i - 1][j - 1] + 2, dp[i - 1][j] + 1,
                               dp[i][j - 1] + 1)  # 三种情况,删除word[i-1],word[j-1],同时删这两者
    return dp[-1][-1]

72.编辑距离

题目大意:

给你两个单词 word1word2请返回将 word1 转换成 word2 所使用的最少操作数

操作数包括(增加,删除,修改)

同583类似,当word1[i-1] != word2[j-1]时

  1. 修改操作 dp[i] [j] = dp[i-1] [j-1] + 1
  2. 删除操作 dp[i-1] [ j] + 1
  3. 增加操作 dp[i] [j-1] + 1
def minDistance(self, word1: str, word2: str) -> int:
    len1, len2 = len(word1), len(word2)
    # dp[i][j] 表示以i-1, j-1结尾的字符串的最段编辑距离
    dp = [[0 for _ in range(len2 + 1)] for _ in range(len1 + 1)]
    for i in range(len2 + 1):
        dp[0][i] = i
    for j in range(1, len1 + 1):
        dp[j][0] = j
    # 状态转移
    for i in range(1, len1 + 1):
        for j in range(1, len2 + 1):
            if word1[i - 1] == word2[j - 1]:
                dp[i][j] = dp[i - 1][j - 1]
            else:
                dp[i][j] = min(dp[i - 1][j - 1] + 1, dp[i - 1][j] + 1, dp[i][j - 1] + 1)    # 三种情况
    return dp[-1][-1]

回文专题

回文最需要注意的一点就是遍历的顺序非常重要

如果我们要判断dp[i] [j]是否回文,就需要知道dp[i+1] [j-1]是否回文

所以这就要求遍历的顺序是 从下到上, 从左到右

然后求上三角矩阵的状态转移即可

647.回文子串

题目大意:给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。

def countSubstrings1(self, s: str) -> int:
    n = len(s)
    dp = [[False for _ in range(n)] for _ in range(n)]  # dp[i][j]表示i-j范围的子串是否是回文串
    for i in range(n):  # 初始化
        dp[i][i] = True  # 自身一定是回文串
    res = n
    # 状态转移只看上三角矩阵 注意遍历顺序:从上到下,从左到右
    for j in range(1, n):  # 控制列
        for i in range(j):  # 控制行
            if s[i] != s[j]:
                dp[i][j] = False
            elif s[i] == s[j]:
                if j - i == 1:
                    dp[i][j] = True
                    res += 1
                else:
                    if dp[i + 1][j - 1]:
                        dp[i][j] = True
                        res += 1
    return res

516.最长回文子序列

题目大意:给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。

def longestPalindromeSubseq(self, s: str) -> int:
    n = len(s)
    dp = [[0 for _ in range(n)] for _ in range(n)]
    for i in range(n):
        dp[i][i] = 1
    # 注意遍历顺序, 02需要用到12,所以需要从下到上,从左到右遍历
    for j in range(1, n):
        for i in range(j - 1, -1, -1):
            if s[i] == s[j]:
                dp[i][j] = dp[i + 1][j - 1] + 2
            else:
                dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])
    return dp[0][n - 1]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值