【动态规划-备忘录法】最长公共子序列(输出所有解) 思路解析和代码

本文介绍了如何使用备忘录法和动态规划解决最长公共子序列问题,详细解析了思路、注意事项,并提供了个人的递归与递推式代码实现,包括如何通过回溯输出所有解。
摘要由CSDN通过智能技术生成

最长公共子序列

上一篇动态规划总结

个人思路

对比备忘录方法(递归)和动态规划(递推)

备忘录方法
  • 备忘录方法要用递归实现
  • 递归是自顶向下的解决问题的:即从目标开始,将问题划分,对子问题求解,直到边界
  • 递归前对备忘录进行查询,当前备忘录未被填写时,则进行递归,否则直接返回备忘录的内容(核心,提高算法效率)
  • 当整个问题的求解过程中有大量子问题无需求解时,备忘录更省时
  • 一般要对备忘录进行初始化,为了之后快速判断是否有已经填写过备忘录
动态规划递推式
  • 通过循环实现
  • 递推式是自下而上解决问题的:即从边界开始,逐步对问题求解,直到抵达目标
  • 当整个问题的求解过程中全部都要进行计算时,则应该使用递推式

思路

dp[i][j]表示字符串1长度为i与字符串2长度为j的最长公共子序列

自顶向下分析

  • 求最优解:求的是两个字符串的最长公共子序列
  • 最优子结构:整个字符串的最长公共子序列依赖于其中子串的最长公共子序列,即去掉最后一个或若干个字符,剩下的字符串所记录的值仍然是最长公共子序列
  • 重叠子问题:计算过程中会多次比较两个字符串的子串

自下而上解决问题

  • 边界:两个字符串出现空串时,最长公共子序列为0,即dp[i][0]和dp[0][i]均为0,i的取值范围是0~两个字符串各自的长度
  • 状态转移:
    • 当两个字符串当前位置字符相等时,str[i ]==str[j],最长公共子序列要在两个字符串各自的上一位基础上+1,即dp[i][j] = dp[i - 1][j - 1] + 1
    • 当两个字符串当前位置字符不相等时,str[i]!=str[i],最长公共子序列无法继续延长,则继承dp[i][j - 1],dp[i - 1][j]的最大值,即dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
  • 时间复杂度:O(m * n),m,n为字符串的长度

注意

  • i,j表示的是长度,访问元素的时候需-1
  • 回溯法输出所有解:
    • 从dp备忘录的最后一位开始回溯
    • 若当前位置数值与其左侧位置数值相同时,说明从左侧转移到当前位置的LCS没有延长
    • 若当前位置数值与其上侧位置数值相同时,说明从上侧转移到当前位置的LCS没有延长
    • 若当前位置数值与其上侧、左侧均不相同,说明此时LCS得到延长,应记录当前位置所对应的字符
  • 最后要注意回溯法是逆序遍历,因此输出时要逆序输出

个人思路代码

备忘录方法+回溯输出所有解
/*
 * @Author: LLX 
 * @Date: 2020-10-31 19:19:33 
 * @Last Modified by: SEUer
 * @Last Modified time: 2020-10-31 19:20:11
 */
#include<bits/stdc++.h>
using namespace std;
//dp[i][j]表示字符串1长度为i与字符串2长度为j的最长公共子序列
//i,j表示的是长度,访问元素的时候需-1
string str1, str2;
int len1, len2;
string ans;//存放具体的最大公共子序列
int lcs;//存放最大公共子序列的长度
void findLCS(vector<vector<int> >& dp, int x, int y){
   
    if(x <= 0 || y <= 0){
   
        if(ans.size() == lcs){
   
            reverse(ans.begin(), ans.end());
            cout << "lcs:" << ans << endl;
        }
      
  • 2
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值