代码随想录训练营第57天 | 647. 回文子串 ● 516.最长回文子序列

647. 回文子串  

题目链接:https://leetcode.com/problems/palindromic-substrings

解法:

这道题代码量不大,但是要每一步都需要认真考虑。

1. 定义dp[i][j]的含义

dp[i][j]:表示区间范围[i,j] (注意是左闭右闭)的子串是否是回文子串,如果是,则dp[i][j]为true,否则为false。

这里dp不再直接对应问题:dp[i] 为 下标i结尾的字符串有 dp[i]个回文串。这样找不到递推关系。

2. 递推关系

如果s[i] = s[j] 且 j - i <= 2,比如:a,aa,aba,那么都是回文子串。如果j - j > 2,那么如果s[i+1:j-1] 闭区间是回文子串,那么s[i:j]闭区间也是。

所以条件是 if s[i] == s[j] and (j -i i <= 2 or dp[i+1][j-1]),则dp[i][j] = True

3. 遍历顺序

由于需要提前得到dp[i+1][j-1],那么i的遍历是从右到左。

也可以用双指针降低空间复杂度。

首先确定回文串,就是找中心然后向两边扩散看是不是对称的就可以了。

在遍历中心点的时候,要注意中心点有两种情况

一个元素可以作为中心点,两个元素也可以作为中心点。

边界条件:无

时间复杂度:动态规划O(n^2), 双指针O(n^2)

空间复杂度:动态规划O(n^2), 双指针O(1)

class Solution(object):
    def countSubstrings(self, s):
        dp = [[False] * len(s) for _ in s]
        result = 0
        for i in range(len(s), -1, -1):
            for j in range(i, len(s)):
                if s[i] == s[j] and (j-i<=2 or dp[i+1][j-1]):
                    result += 1
                    dp[i][j] = True
        return result
# 双指针版本
class Solution(object):
    def countSubstrings(self, s):
        result = 0
        for i in range(len(s)):
            result += self.extend(s, i, i)
            result += self.extend(s, i, i+1)
        return result

    def extend(self, s, i, j):
        result = 0
        while i >= 0 and j < len(s) and s[i] == s[j]:
            i -= 1
            j += 1
            result += 1
        return result

516.最长回文子序列

题目链接:https://leetcode.com/problems/longest-palindromic-subsequence/

解法:

1. 确定dp数组(dp table)以及下标的含义

dp[i][j]:字符串s在[i, j]范围内最长的回文子序列的长度为dp[i][j]

2. 确定递推公式

在判断回文子串的题目中,关键逻辑就是看s[i]与s[j]是否相同。

如果s[i]与s[j]相同,那么dp[i][j] = dp[i + 1][j - 1] + 2.

如果s[i]与s[j]不相同,加入s[j]的回文子序列长度为dp[i + 1][j]。加入s[i]的回文子序列长度为dp[i][j - 1]。那么dp[i][j]一定是取最大的,即:dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])。

3. 初始化

dp[i][i] = 1,其他为0,比如dp[3][2],由于s[3:2]是不可能取到了,也初始化为0。

其他需要注意的点就是对j的遍历是从i+1开始,而不是i+2,尽管dp[i+1][j-1]在i+1时,截取字符串是不行的。

最后是返回dp[0][-1],因为这表示整条字符串。

边界条件:无

时间复杂度:O(n^2)

空间复杂度:O(n^2)

class Solution(object):
    def longestPalindromeSubseq(self, s):
        dp = [[0] * len(s) for _ in s]
        for i in range(len(s)):
            dp[i][i] = 1
        for i in range(len(s)-1, -1, -1):
            for j in range(i+1, len(s)):
                # s[i] = s[j] 的情况,如果 s[3][2]是不行的,
                # 所以dp[3][2]初始化为0了,于是下边也可运行
                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][-1]

你可能感兴趣的:(数据结构和算法,算法,数据结构)