最长回文子序列问题的原理与实现:动态规划的又一经典应用

这篇具有很好参考价值的文章主要介绍了最长回文子序列问题的原理与实现:动态规划的又一经典应用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

回文是指一个正着读和反着读都一样的字符串,比如 “aba” , “racecar” , “madam” 等。回文有许多有趣的性质和应用,比如在密码学,生物信息学,数据压缩等领域都有涉及。

那么,给定一个字符串,如何找出它的最长回文子序列呢?最长回文子序列是指从原字符串中删除一些元素(也可以不删除)后得到的最长的回文字符串。

例如,对于字符串 “abcbda” ,它的最长回文子序列是 “abba” ,长度为 4 。

最长回文子序列长度问题第一种解法就是求原字符串与其逆序字符串的最大公共子序列长度。关于最大公共子序列长度在上篇博客已经给出解释说明,在这里我们讨论另一种解法。

最长回文子序列问题可以用动态规划算法在多项式时间内解决,其基本思想是利用一个二维数组来存储字符串中任意两个位置之间的最长回文子序列的长度,然后根据递推公式来更新数组的值,最后回溯数组来找出最长回文子序列。

具体来说,假设我们有一个字符串 S = s1s2…sn ,我们定义一个二维数组 L[i,j] 表示 S 的第 i 个元素到第 j 个元素之间的最长回文子序列的长度,则我们有以下递推公式:

  • 如果 i > j ,则 L[i,j] = 0 ,因为空字符串没有回文子序列。
  • 如果 i = j ,则 L[i,j] = 1 ,因为单个字符是回文子序列。
  • 如果 i < j ,则:
    • 如果 si = sj ,则 L[i,j] = L[i+1,j-1] + 2 ,因为 si 和 sj 可以作为最长回文子序列的首尾元素。
    • 如果 si != sj ,则 L[i,j] = max(L[i+1,j], L[i,j-1]) ,因为 si 和 sj 不可能同时属于最长回文子序列。

根据这个递推公式,我们可以从右下角开始填充数组 L ,直到左上角得到 L[1,n] ,即为 S 的最长回文子序列的长度。然后,我们可以从左上角开始回溯数组 L ,根据以下规则来找出最长回文子序列:

  • 如果 si = sj ,则 si 或 sj 是最长回文子序列的一个元素,将其加入结果中,并向右下方移动一格。
  • 如果 si != sj ,则比较 L[i+1,j] 和 L[i,j-1] 的大小,向较大值所在的方向移动一格。
  • 如果 i > j 或 i = j ,则停止回溯。

下面是一个例子,假设我们有一个字符串 S = “abcbda” ,我们可以按照上述方法求出它的最长回文子序列长度和内容:

S 的最长回文子序列长度为 4 ,且有一个最长回文子序列,即 “abba” 。

下面是用 Python 语言实现的动态规划算法的代码:

def LPSLength(S):
    # 初始化二维数组 L
    n = len(S)
    L = [[0] * (n + 1) for _ in range(n + 1)]
    
    # 填充数组 L
    for i in range(1, n + 1):
        for j in range(1, n + 1):
            if i > j:
                L[i][j] = 0
            elif i == j:
                L[i][j] = 1
            else:
                if S[i - 1] == S[j - 1]:
                    L[i][j] = L[i + 1][j - 1] + 2
                else:
                    L[i][j] = max(L[i + 1][j], L[i][j - 1])
    
    # 返回最长回文子序列的长度
    return L[1][n]

def LPS(S):
    # 获取二维数组 L
    n = len(S)
    L = LPSLength(S)
    
    # 初始化结果字符串
    result = ""
    
    # 回溯数组 L
    i = 1
    j = n
    while i <= j:
        if S[i - 1] == S[j - 1]:
            result = S[i - 1] + result # 将匹配的元素加入结果中
            i += 1
            j -= 1
        else:
            if L[i + 1][j] > L[i][j - 1]:
                i += 1
            else:
                j -= 1
    
    # 返回最长回文子序列
    return result

# 测试
S = "abcbda"
print(LPSLength(S)) # 输出 4
print(LPS(S)) # 输出 abba

另外,还有一种令人简单理解的递归代码实现:

# 原字符串与其逆字符串的最长公共子序列既是最长回文子序列

# 在l与r范围内最长回文子序列长度
def process(l,r):
    if l==r:
        return 1
    if l==r-1:
        return 2 if s[l]==s[r] else 1
    p1=process(l,r-1)
    p2=process(l+1,r)
    p3=process(l+1,r-1)+2 if s[l+1]==s[r-1] else process(l+1,r-1)
    return max(p1,p2,p3)

def longestHuiwen(s):
    if len(s)==0 and s==None:
        return 0
    if len(s)==1:
        return 1
    if len(s)==2:
        return 2 if s[0]==s[1] else 1

    return process(0,len(s)-1)

s='12a33211'
print(longestHuiwen(s))

以上就是最长回文子序列问题的原理与实现的介绍,希望对您有所帮助。如果您有任何疑问或建议,欢迎在评论区留言,谢谢您的阅读!😊文章来源地址https://www.toymoban.com/news/detail-412049.html

到了这里,关于最长回文子序列问题的原理与实现:动态规划的又一经典应用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 算法打卡day49|动态规划篇17| Leetcode 647. 回文子串、516.最长回文子序列

    Leetcode 647. 回文子串 题目链接:647. 回文子串 大佬视频讲解:647. 回文子串视频讲解  个人思路  这道题的dp数组有点难找到关联,以至于递归关系也不好找,所以看题解吧... 解法 动态规划 动规五部曲: 1.确定dp数组(dp table)以及下标的含义 一般在定义dp数组的时候 会根据题

    2024年04月22日
    浏览(35)
  • day57|动态规划17-最长回文子串问题

    回文子串:强调连续 回文子序列:不强调连续 暴力思路:三层for循环 双指针思路: 动态规划 dp数组 dp[i][j]: 根据字符串的形式和所解决的问题确定dp数组的形式和含义。 递归公式 (分情况讨论) 2.1 如果 i j 2.2 如果 j-i 1 2.3 如果 j-i1: 此时依赖于dp[i+1][j-1]是不是一个回文子

    2024年02月09日
    浏览(31)
  • 动态规划---最长连续子序列问题

    最长连续子序列问题算是动态规划问题中的一个小分支,这里单独写一篇文章介绍。至于动态规划基础问题和详细的处理步骤我在我的另一篇文章中详细介绍过。具体解决步骤请移步观看——动态规划基础篇。如果想了解01背包问题和滚动数组相关内容请移步观看——动态规

    2024年02月15日
    浏览(27)
  • 【动态规划】求最长递增子序列问题

    最长递增子序列(Longest Increasing Subsequence, LIS ) 子序列:对于任意序列s,它的子序列是通过删除其中零个或多个元素得到的另⼀个序列 注:剩余元素的相对顺序保持不变 给定n个整数组成的序列 s [ 1... n ] s[1...n] s [ 1... n ] ,求最长递增子序列LIS(的长度) 8 3 6 1 3 5 4 7 假设

    2024年02月03日
    浏览(40)
  • 动态规划-----最长公共子序列(及其衍生问题)

    目录 一.最长公共子序列的基本概念: 解决动态规划问题的一般思路(三大步骤): 二.最长公共子序列题目: 三.字符串的删除操作: 四.最小 ASCII 删除和: 首先需要科普一下,最长公共子序列(longest common sequence)和最长公共子串(longest common substring)不是一回事儿。什么

    2024年03月26日
    浏览(36)
  • 动态规划应用篇:详解最长公共子序列问题

    动态规划 是一个强大的工具,将复杂问题 分解 为多个容易解决的子问题,并且会对中间结果进行存储从而避免重复计算,然后将它们的解组合起来,形成大问题的解,高效地得出 全局最优解 。前面我们已经了解了动态规划的基础知识及一维动态规划问题的求解,今天,我

    2024年04月15日
    浏览(36)
  • 【算法(四·三):动态规划思想——最长公共子序列问题】

    最长公共子序列(Longest Common Subsequence,简称LCS)问题是一种常见的字符串处理问题。它的**目标是找到两个或多个字符串中的最长公共子序列,这个子序列不需要是连续的,但字符在原始字符串中的相对顺序必须保持一致。**例如,考虑两个字符串\\\"ABCD\\\"和\\\"ACDF\\\",它们的最长公

    2024年04月13日
    浏览(39)
  • 【动态规划】最长公共子序列Python实现

    个人主页:丷从心 系列专栏:动态规划算法 问题描述 给定两个序列 X = {   x 1 , x 2 , ⋯   , x m   } X = set{x_{1} , x_{2} , cdots , x_{m}} X = { x 1 ​ , x 2 ​ , ⋯ , x m ​ } 和 Y = {   y 1 , y 2 , ⋯   , y n   } Y = set{y_{1} , y_{2} , cdots , y_{n}} Y = { y 1 ​ , y 2 ​ , ⋯ , y n ​ } ,找出 X X X

    2024年02月20日
    浏览(37)
  • 动态规划-最长回文子串

    突然觉得很有必要将学过的内容记录下来,这样后续在需要用到的时候就可以避免从头进行学习,而去看自己之前做过的笔记无疑是效率更高的方法。 而作为计算机专业的学生,纸质笔记无法很好的进行记录,像写代码、画图、画表都是很麻烦的,而且纸质的很容易丢,因此

    2024年04月14日
    浏览(28)
  • 动态规划——最长回文子串

    给你一个字符串 s ,找到 s 中最长的回文子串。 如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。 示例 1: 示例 2: 1、动态规划算法 解题思路 (1)考虑 回文串的性质 :若一个子串是回文串并且 长度大于2 ,则将其 首尾两个字母去除 后,该子串仍然是一

    2024年04月08日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包