代码随想录算法训练营第五十七天|647 回文子串 516.最长回文子序列

本文介绍了两种在LeetCode平台上常见的与回文字符串相关的问题,分别是查找回文子串的数量和最长回文子序列的长度。作者详细阐述了使用动态规划的方法来优化时间复杂度,分别针对连续和不连续情况的处理策略。
摘要由CSDN通过智能技术生成

647. 回文子串

https://leetcode.com/problems/palindromic-substrings/

思路: 当我们看到两个下标 i, j 上 s[i] != s[j], 那么 s[i: j+1] 一定不是回文子串。 如果s[i] == s[j], 那么我们可以在检查 s[i+1: j] 是不是回文串。如果暴力搜索的话是 O(n^3) 的时间复杂度。 我们可以用一个二维 dp 数组记录s[i: j+1] 是不是回文串。 然后用 一个 visited 数组记录我们是不是已经经历过 i,j 的组合。 然后开始深度优先搜索, 如果visited[i][j] == 1, 我们直接返回 dp[i][j].  然后如果visited[i][j] == 0, 我们碰到 s[i] != s[j], 那么 visited 数组变成 1, dp 数组填0. 如果我们碰到s[i] == s[j] 并且 j-i < 2, 那么visited 数组标记为1, dp 数组为1.  如果s[i] == s[j] 并且 j-i >= 2, 然后我们搜索 s[i+1: j]. dp[i][j] 等于搜索的返回值。 

难点: 如何降低时间复杂度。 

class Solution:
    def countSubstrings(self, s: str) -> int:
        matrix = [[0] * len(s) for _ in range(len(s))]
        visited = matrix.copy()
        def fds(s: str, i: int, j: int):
            if visited[i][j]:
                return matrix[i][j]
            visited[i][j] = 1
            if s[i] != s[j]:
                matrix[i][j] = 0
            elif s[i] == s[j] and j - i <= 1:
                matrix[i][j] = 1
            else:
                matrix[i][j] = fds(s, i+1, j-1)
            return matrix[i][j]
        
        for i in range(0, len(s)):
            for j in range(i, len(s)):
                fds(s, i, j)
        return sum([sum(x) for x in matrix])
            

516.最长回文子序列

https://leetcode.com/problems/longest-palindromic-subsequence/description/

思路: 这个问题和上一个问题挺类似的。 不同点在于回文子序列是要考虑不连续的情况。 如果是回文串, 直接用上一题的代码, 最后找出 max(j-i)。  如果是序列, 其实就是找到 s 和 s[::-1]的最长公共子序列。 不过这个问题不转换成 LCS 也可以直接解决。 考虑dp[i][j] 表示 s[i: j+1] 的最长回文子序列长度。 如果 s[i] != s[j], 那么dp[i][j] = max(dp[i+1][j], dp[i][j-1]). 如果 s[i] == s[j], 那我们再分情况, j - i < 2, dp[i][j] = j - 1 +1. 如果 j - i >= 2, dp[i][j] = dp[i+1][j-1] + 2. 这里注意递推的顺序, 所以 循环的时候 i 从 len(s-1) 到 0, j 从 i 到 len(s-1), 保证用递推关系的时候, 前置的状态已经计算过了。 

难点: 注意一下循环的顺序

class Solution:
    def longestPalindromeSubseq(self, s: str) -> int:
        dp = [[0] * len(s) for _ in range(len(s))]
        for i in range(len(s)-1, -1, -1):
            for j in range(i, len(s)):
                if s[i] != s[j]:
                    dp[i][j] = max(dp[i+1][j], dp[i][j-1])
                elif s[i] == s[j] and j - i < 2:
                    dp[i][j] = j - i + 1
                else:
                    dp[i][j] = dp[i+1][j-1] + 2
        return dp[0][len(s)-1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值