当前位置: 首页 > news >正文

回文子串 与 回文子序列?数量?最长的情况?

文章目录

  • 回文子串
    • 求解方案数
    • 求解最值
  • 回文子序列
    • 求解方案数
    • 求解最值(最大长度)

  • 回文的情况就是,从左边读和从右边读是一样的,总的来说,就是关于中间是对称的
  • 在这里又分为 回文子串回文子序列 两种题型
    • 回文子串:要求在原来的字符串中由连续的元素组成
    • 回文子序列:可以删除原来的字符串中的某些元素,可以挑着来选元素
  • 回文子串和回文子序列分为又细分为两种题型 求解方案数求解最长的情况(长度+直接返回具体的元素)

回文子串

回文子串:其实限制很大,当端点不等,那么s[i]-s[j]直接不满足,如果相等,还得看这个s[i+1]-s[j-1]的情况!,所以强调的是一个是否的问题!

求解方案数

LCR.020.回文子串

在这里插入图片描述

思路分析:属于区间dp的问题

  • 定义dp[i][j]表示原来的字符串s[i]-s[j]是否是回文子串
    def countSubstrings(self, s: str) -> int:
        # 求解的是回文子串的数量
        # 使用区间dp,d[i][j] 定义为 s[i]到s[j]是否是回文字符串
        n = len(s)
        dp = [[0]*n for _ in range(n)]

        # 当相等的时候,dp[i][j] = dp[i+1][j-1],否则就是0
        ans = 0
        for i in range(n-1,-1,-1):
            dp[i][i] = 1
            ans+=1
            for j in range(i+1,n):
                if s[i] == s[j]:
                    if j == i+1:
                        # 长度为2的得先处理
                        dp[i][j] = 1
                        ans+=1
                        continue
                    dp[i][j] = dp[i+1][j-1]
                    if dp[i][j]:
                        ans+=1
        return ans

求解最值

5.最长回文子串

在这里插入图片描述

思路分析:可以参照这个上面那个求解方案数的思路

  • 还是定义dp[i][j]为 原来的字符串s[i]-s[j]是否构成回文子串,遍历完一遍之后,我们再对这个二维的dp数组进行遍历,记录dp[i][j]==1,那么此时这个start = i ,end = j,记录长度最长的情况end-start+1的时候
class Solution:
    def longestPalindrome(self, s: str) -> str:
        # 直接暴力做法
        n = len(s)
        # 还是老样子,定义dp[i][j]为s[i]到s[j]是否是回文子串
        dp = [[0]*n for _ in range(n)]

        for i in range(n-1,-1,-1):
            dp[i][i] = 1
            for j in range(i+1,n):
                if s[i]==s[j]:
                    if j - i ==1:
                        dp[i][j] = 1
                    else:
                        dp[i][j] = dp[i+1][j-1]
        start,end = 0,0
        maxlen = 0
        # 开始遍历,这里有一个巧妙的地方就是:
        # 当dp[i][j] == 1的时候,回文子串的长度就是j-i+1
        for i in range(n):
            for j in range(n):
                if dp[i][j] :
                    l = j-i + 1
                    if l>maxlen:
                        maxlen=l
                        start=i
                        end=j 
        return s[start:end+1]
  • 也可以用马拉车算法

回文子序列

求解方案数

730.统计不同回文子序列

在这里插入图片描述

思路分析:还是区间dp的思路

  • 定义dp[i][j]s[i]到s[j]的非空回文子序列的数量
  • nusm[i]==nums[j]时,dp[i][j]=dp[i+1][j-1] * 2 + 2,理论上是这个转移公式,但是得排除这个dp[i+1][j-1]里面还存在nums[i] 和 nums[j]对称的情况,如果需要减去对应重复的情况
  • 当不相等的时候dp[i][j] = dp[i+1][j] + dp[i][j-1] - dp[i+1][j-1]
class Solution:
    def countPalindromicSubsequences(self, s: str) -> int:
        # 区间dp求解方案数的问题
        # 定义dp[i][j] 为原来的序列中,s[i] 到 s[j]中
        mod = 10**9 + 7
        n = len(s)
        dp = [[0] * n for _ in range(n)]
        for i in range(n-1, -1, -1):
            dp[i][i] = 1  # 单个字符是一个回文子序列
            for j in range(i+1, n):
                if s[i] == s[j]:
                    # 找到左右边界,避免重复计数
                    left = i + 1
                    right = j - 1
                    # 找到第一个等于 s[i] 的字符
                    while left <= right and s[left] != s[i]:
                        left += 1
                    # 找到第一个等于 s[j] 的字符
                    while left <= right and s[right] != s[j]:
                        right -= 1
                    if left > right:
                        # 没有重复字符
                        dp[i][j] = dp[i+1][j-1] * 2 + 2
                    elif left == right:
                        # 只有一个重复字符,那么删除的是单独的nums[i]
                        dp[i][j] = dp[i+1][j-1] * 2 + 1
                    else:
                        # 有多个重复字符,存在重复计数的过程
                        dp[i][j] = dp[i+1][j-1] * 2 - dp[left+1][right-1]
                else:
                    dp[i][j] = dp[i+1][j] + dp[i][j-1] - dp[i+1][j-1]
                dp[i][j] %= mod  # 取模
                if dp[i][j] < 0:
                    dp[i][j] += mod  # 确保结果是非负的
        return dp[0][n-1]

求解最值(最大长度)

516.最长回文子序列

在这里插入图片描述

思路分析:区间dp

  • 定义dp[i][j]表示是s[i]-s[j]的子序列的最大长度
  • 区别于回文子串是与不是,这个子序列存在更大的可能性
  • nums[i]==nums[j],那么dp[i][j] = dp[i+1][j-1] + 2,否则就是只能选一个端点,dp[i][j] = max(dp[i+1][j],dp[i][j-1])
class Solution:
    def longestPalindromeSubseq(self, s: str) -> int:
        n = len(s)
        dp = [[0]*n for _ in range(n)]
        # dp[i][j]定义的是原来的字符串中s[i]到s[j]之间的最长的回文子序列的最大长度
        for i in range(n-1,-1,-1):
            dp[i][i] = 1
            for j in range(i+1,n):
                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]

相关文章:

  • 深度解析基于Transformer的LLaMA2模型结构:从分词到推理的完整流程
  • xss漏洞
  • HashMap如何实现线程安全
  • leetcode 76. 最小覆盖子串
  • Materials Studio MS2020在linux系统上的安装包下载地址 支持centos Ubuntu rocky等系统
  • 爬虫系列之【数据解析之正则】《二》
  • 神经网络之CNN文本识别
  • LeetCode 热题100 3. 无重复字符的最长子串
  • LabVIEW DataSocket 通信库详解
  • 基于DeepSeek 的图生文最新算法 VLM-R1
  • Go开发框架Sponge+AI助手协同配合重塑企业级开发范式
  • 论文阅读:CAN GENERATIVE LARGE LANGUAGE MODELS PERFORM ASR ERROR CORRECTION?
  • 【C语言显示Linux系统参数】
  • c++面试常见问题:虚表指针存在于内存哪个分区
  • LeetCodehot 力扣热题100 组合总和
  • 【C】初阶数据结构8 -- 链式二叉树
  • 计算机毕业设计SpringBoot+Vue.js人力资源管理系统(源码+文档+PPT+讲解)
  • MCP与RAG:增强大型语言模型的两种路径
  • 【算法】【并查集】acwing算法基础837. 连通块中点的数量
  • 每日一题——接雨水
  • 第78届世界卫生大会20日审议通过“大流行协定”
  • 新四军老战士、苏州市文联原副主席张景坤逝世
  • “高原笑匠”、西藏著名表演艺术家扎西顿珠去世
  • 上海电视节发布海报、宣传片:三十而励,光影新程
  • 国家发改委:系统谋划7方面53项配套举措,推动民营经济促进法落地见效
  • 欧洲加大力度招募美国科研人员