leetcode(8)回文系列题目

动态规划:

647. 回文子串

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

  • 当s[i]与s[j]不相等,dp[i][j]一定是false。
  • 当s[i]与s[j]相等时,有如下三种情况
    • 情况一:下标i 与 j相同,同一个字符例如a,当然是回文子串
    • 情况二:下标i 与 j相差为1,例如aa,也是回文子串
    • 情况三:下标:i 与 j相差大于1的时候,例如cabac,此时s[i]与s[j]已经相同了,这个区间是不是回文就看dp[i + 1][j - 1]是否为true。

根据dp[i + 1][j - 1]是否为true,再对dp[i][j]进行赋值true的。

dp[i + 1][j - 1] 在 dp[i][j]的左下角,如图:

所以一定要从下到上,从左到右遍历,这样保证dp[i + 1][j - 1]都是经过计算的

        length = len(s)
        dp = [[False] * length for _ in range(length)]
        res = 0
        for i in range(length - 1, -1, -1):  #注意遍历顺序
            for j in range(i, length):
                if s[i] == s[j]:
                    if j - i <= 1 or dp[i + 1][j - 1] :  #注意两个判断条件的顺序
                        res += 1
                        dp[i][j] = True
        return res

516. 最长回文子序列

注意:与 647. 回文子串 的区别是回文子串是要连续的,回文子序列可以不连续

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

  • 如果s[i]与s[j]不相同,说明s[i]和s[j]的同时加入 并不能增加[i,j]区间回文子串的长度,那么分别加入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]);

        length = len(s)
        dp = [[0] * length for _ in range(length)]
        for i in range(length):
            dp[i][i] = 1
        for i in range(length - 1, -1, -1):
            for j in range(i + 1, length): #注意从i+1开始遍历
                if s[i] == s[j]:
                    dp[i][j] = dp[i + 1][j - 1] + 2
                else:
                    dp[i][j] = max(dp[i][j - 1], dp[i + 1][j])
        return dp[0][-1]

5. 最长回文子串

注意:与 647. 回文子串 的区别是当是回文串的时候更新起始位置并记录最大长度

class Solution:
    def longestPalindrome(self, s: str) -> str:
        n = len(s)
        dp = [[0] * n for _ in range(n)]
        left, right = 0, 0
        maxL = float('-inf')
        for i in range(n, -1, -1):
            for j in range(i, n):
                if s[i] == s[j]:
                    if j - i <= 1 or dp[i + 1][j - 1] == 1:
                        dp[i][j] = 1
                if dp[i][j] == 1 and j-i+1 > maxL:
                    left, right = i, j
                    maxL = j-i+1
        return s[left: left + maxL]

125. 验证回文串

双指针,里面的判断部分还可以再优化一下

class Solution:
    def isPalindrome(self, s: str) -> bool:
        s = s.lower()
        # print(s)
        left, right = 0, len(s) - 1
        while left <= right:
            while left < len(s) and not (s[left].isalpha() or s[left].isdigit()):
                left += 1
            while right >= 0 and not (s[right].isalpha() or s[right].isdigit()):
                right -= 1
            if left == len(s) or right == -1:
                return True
            if s[left] != s[right]:
                return False
            left += 1
            right -= 1
        return True

双指针:

647. 回文子串

posted @ 2022-05-13 16:36  YTT77  阅读(38)  评论(0编辑  收藏  举报