回文子串问题梳理

https://leetcode.cn/problems/palindromic-substrings/
https://leetcode.cn/problems/longest-palindromic-subsequence/
https://leetcode.cn/problems/palindrome-partitioning/description/
https://leetcode.cn/problems/longest-palindromic-substring/description/
https://leetcode.cn/problems/palindrome-linked-list-lcci/submissions/516340933/

抽象思路:

做任何事都要有个起点,回文子串类型题目的起点就是任意一个可能的节点。也就是说对于区间s[i:j]是否是个回文,就要看这区间里面的s[i+1:j-1]是不是回文,还有s[i]和s[j]是否相等。

647. 回文子串

给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。
回文字符串 是正着读和倒过来读一样的字符串。
子字符串 是字符串中的由连续字符组成的一个序列。

思路:

求字符串内回文子串的数量。首先要考虑我们要知道某个区间是否为回文子串;如果知道某个区间是回文,那就知道了所有可能的区间里有多少是回文子串。题目也就迎刃而解。

具体做法:

动态规划

五部曲
1.确定dp的维度大小,元素的意义
因为不需要从外面推导出里面,而是从里面往外面扩散推导,所以不需要n+1,n为字符串长度。这里用二维数组比较好理解不同的区间范围。
dp[i][j]代表s[i:j]是否为回文子串,值是true或false

2.状态转移方程
条件1:s[i]和s[j]是否相等。不相等,那就为false,肯定不是回文子串;如果相等,进入以下条件
条件2:默认满足条件1
条件2.1:如果i==j,说明是单个字符,肯定是回文子串
条件2.2:如果abs(i-j)<=2,说明是两个或三个字符,肯定是回文子串(“aa”,“aba”)(跟2.1合并)
条件2.3:如果不满足上述两个条件,说明至少是"axxa",x代表未知
条件2.3.1:如果"xx"是回文子串,反映到状态上是dp[i+1][j-1]是true,那当前状态也是true
条件2.3.2:跟2.3.1相反

3.初始化边界
不必对边界初始化,全部设置为false,代表没计算

4.遍历顺序
一般都是从上到下,从左到右。但是本题的推导是从dp[i+1][j-1]开始的,如果先计算dp[i][j]就会得不到正确的基准推导。
所以要从下到上,从左到右,从左下角遍历到右上角,中间不要重复计算。

5.手动推理

代码:

class Solution:
    def countSubstrings(self, s: str) -> int:

        # 定义状态二维数组,dp[i][j]代表s[i:j]是回文子串
        n = len(s)
        dp = [[False for _ in range(n)] for _ in range(n)]
        res = 0 # 结果计数

        # 状态要从dp[i+1][j-1]得到,所以要先计算左下角的
        # 从下到上,从左往右
        for i in range(n-1, -1, -1): # 从下到上
            for j in range(i, n): # 从左往右
                if s[i] == s[j]:# 条件1
                    if abs(i - j) <= 2: # 条件2.1 2.2
                        res += 1
                        dp[i][j] = True
                    elif dp[i+1][j-1]: # 条件2.3
                        res += 1
                        dp[i][j] = True
        
        return res

你可能感兴趣的:(算法,python)