[动态规划]——线性DP(LIS/LCS/LCIS等) 详解

这篇具有很好参考价值的文章主要介绍了[动态规划]——线性DP(LIS/LCS/LCIS等) 详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【引入】

线性DP,是较常见的一类动态规划问题,其是在线性结构上进行状态转移,这类问题不像背包问题、区间DP等有固定的模板

线性动态规划的目标函数为特定变量的线性函数,约束是这些变量的线性不等式或等式,目的是求目标函数的最大值或最小值

因此,除了少量问题(如:LIS、LCS、LCIS等)有固定的模板外,大部分都要根据实际问题来推导得出答案

【常见问题】

(一)序列问题

首先,让我们先了解一下子串子序列还有公共子序列的概念

(1)字符子串:指的是字符串中连续的n个字符,如abcdefg中,ab,cde,fg等都属于它的字串

(2)字符子序列:指的是字符串中不一定连续但先后顺序一致的n个字符,即可以去掉字符串中的部分字符,但不可改变其前后顺序。如abcdefg中,acdg,bdf属于它的子序列,而bac,dbfg则不是,因为它们与字符串的字符顺序不一致

(3)公共子序列:如果序列C既是序列A的子序列,同时也是序列B的子序列,则称它为序列A和序列B的公共子序列。如对序列 1,3,5,4,2,6,8,7和序列 1,4,8,6,7,5 来说,序列1,8,7是它们的一个公共子序列

1.LIS问题——最长上升子序列

最长上升子序列(Longest  Increasing Subsequence),简称LIS,也有些情况求的是最长非降序子序列,二者区别就是序列中是否可以有相等的数,对于固定的数组,虽然LIS序列不一定唯一,但LIS的长度是唯一的

状态设计:dp[i]代表以a[i]结尾的LIS的长度

状态转移:dp[i]=max{dp[j]+1,dp[i]} (1<=j< i,a[j]<a[i])

边界处理:dp[i]=1(1<=i<=n)

时间复杂度:O (n^2)

模板:

#include<iostream> 
using namespace std;

const int N=105;
int a[N],dp[N];
int main(){
    int n,ans=0;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        dp[i]=1;
    }
    for(int i=1;i<=n;i++){
    	for(int j=1; j<i; j++){
    		 if(a[j]<a[i]){
    		 	dp[i] = max(dp[i],dp[j]+1);
			 }
		}
		ans=max(ans,dp[i]);
	}
	cout<<ans;
    return 0;
}

2. LCS问题——最长公共子序列

最长公共子序列,英文缩写为LCS(Longest Common Subsequence)。其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列。对于固定的两个数组,虽然最LCS不一定唯一,但LCS的长度是一定的。查找最长公共子序列与查找最长公共子串的问题不同的地方在于:子序列不需要在原序列中占用连续的位置。最长公共子串(要求连续)和最长公共子序列是不同的

状态设计:dp[i][j]代表以s1[i],s2[j]结尾的LCS的长度

状态转移:

if(s1[i-1]==s2[j-1]){
    dp[i][j]=dp[i-1][j-1]+1;
}else{
    dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
	}

时间复杂度:O(n * m)

模板:

#include<iostream>
using namespace std;

const int N=1005;
int dp[N][N];

int main(){
	string s1,s2;
	cin>>s1>>s2;
	int len1=s1.size(),len2=s2.size(); 
	for(int i=1;i<=len1;i++){
		for(int j=1;j<=len2;j++){
			if(s1[i-1]==s2[j-1]){
				dp[i][j]=dp[i-1][j-1]+1;
			}else{
				dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
			}
		}
	}
	cout<<dp[len1][len2];
	return 0;
}

3. LCIS问题——最长公共上升子序列

状态设计:dp[i, j]表示s1前i个字符和s2前j个字符且以s2[j]为结尾的LCIS

状态方程:对于当处于(s1[i], s2[j])状态时 ,由于dp状态,s2[j]是一定作为这个状态下LCIS的结尾的,所以对于s1[i],就有两种情况,将其纳入LCIS或者不纳入,首先先说不讲a[i]纳入LCIS的情况
(1)若是
s1[i]!=s2[j],显然s1[i]与s2[j]是不能进行配对的,那么问题就缩小成了前s1的前i-1个字符与s2的前j个字符且以s2[j]结尾的LCIS,即dp[i-1, j]也就是说,i之前的以s2[j]结尾的序列自然没有改变,仍然是长度仍然是dp[i−1][j]; 若是s1[i]==s2[i] 如果不想要s1[i]与s2[j]进行配对,是不是也会得到上面的结果,故当s1[i]与s2[j]无法配对时,dp[i, j] = dp[i-1, j]
(2)当s1[i]==s2[j]且它们进行配对时,就要在s1串前i-1个字符和s2的前j-1个字符中找到一个最长的序列,设这个序列以t结尾且b[t]<b[j],是不是就等价于dp[i, j]=max(dp[i-1, t])+1(t >0 &&t<j&&s2[t]<s2[j])

代码:

for(int i=1;i<=n;i++){
    for(int j=1;j<=n;j++){
        dp[i][j]=dp[i-1][j];
        if(a[i]==b[j]){
            for(int k=1;k<j;k++){
            	if(b[j]>b[k]){
                	dp[i][j]=max(dp[i][j],dp[i-1][k]+1);
				}  
			}
        }
    }
}

上面代码的时间复杂度为O(n3),可对其进行O(n2)的优化

待更新......文章来源地址https://www.toymoban.com/news/detail-497803.html

到了这里,关于[动态规划]——线性DP(LIS/LCS/LCIS等) 详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • acwing算法基础之动态规划--线性DP和区间DP

    线性DP:状态转移表达式存在明显的线性关系。 区间DP:与顺序有关,状态与区间有关。 题目1 :数字三角形。 解题思路:直接DP即可, f[i][j] 可以来自 f[i-1][j] + a[i][j] 和 f[i-1][j-1] + a[i][j] ,注意 f[i-1][j] 不存在的情况(最后一个点)和 f[i-1][j-1] 不存在的情况(第一个点)。

    2024年02月04日
    浏览(40)
  • 算法基础复盘笔记Day10【动态规划】—— 线性DP

    ❤ 作者主页:欢迎来到我的技术博客😎 ❀ 个人介绍:大家好,本人热衷于 Java后端开发 ,欢迎来交流学习哦!( ̄▽ ̄)~* 🍊 如果文章对您有帮助,记得 关注 、 点赞 、 收藏 、 评论 ⭐️⭐️⭐️ 📣 您的支持将是我创作的动力,让我们一起加油进步吧!!!🎉🎉 1. 题目

    2023年04月21日
    浏览(69)
  • 猿创征文 |【算法面试入门必刷】动态规划-线性dp(一)

    📦个人主页:一二三o-0-O的博客 🏆技术方向:C/C++客户端资深工程师(直播+音视频剪辑) 👨‍💻作者简介:数据结构算法与音视频领域创作者 📒 系列专栏:牛客网面试必刷 📣专栏目标:帮助伙伴们通过系统训练,掌握数据结构与算法,收获心仪Offer 📝推荐一个找工作

    2024年02月03日
    浏览(38)
  • 猿创征文 |【算法面试入门必刷】动态规划-线性dp(四)

    📦个人主页:一二三o-0-O的博客 🏆技术方向:C/C++客户端资深工程师(直播+音视频剪辑) 👨‍💻作者简介:数据结构算法与音视频领域创作者 📒 系列专栏:牛客网面试必刷 📣专栏目标:帮助伙伴们通过系统训练,掌握数据结构与算法,收获心仪Offer 📝推荐一个找工作

    2024年02月02日
    浏览(28)
  • AcWing算法学习笔记:动态规划(背包 + 线性dp + 区间dp + 计数dp + 状态压缩dp + 树形dp + 记忆化搜索)

    算法 复杂度 时间复杂度0(nm) 空间复杂度0(nv) 代码 算法 通过滚动数组对01背包朴素版进行空间上的优化 f[i] 与 f[i - 1]轮流交替 若体积从小到大进行遍历,当更新f[i, j]时,f[i - 1, j - vi] 已经在更新f[i, j - vi]时被更新了 因此体积需要从大到小进行遍历,当更新f[i, j]时,f[i - 1,

    2024年02月21日
    浏览(35)
  • 【LeetCode: 2369. 检查数组是否存在有效划分 | 暴力递归=>记忆化搜索=>动态规划 | 线性dp】

    🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,CSDN-Java领域新星创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文

    2023年04月19日
    浏览(32)
  • ★动态规划(DP算法)详解

    什么是动态规划:动态规划_百度百科 内容太多了不作介绍,重点部分是无后效性,重叠子问题,最优子结构。 问S-P1和S-P2有多少种路径数,毫无疑问可以先从S开始深搜两次,S-P1和S-P2找出所有路径数,但是当这个图足够大,那就会超时。 动态规划旨在用 空间换时间 ,我们

    2024年02月04日
    浏览(41)
  • 【动态规划】 LIC&LCS

    前段时间再次复习并加深了 LIS 和 LCS 的内容,于是便来写一篇总结。 首先当然是 O ( n 2 ) O(n^2) O ( n 2 ) 的做法。直接把代码放在这里。 最长上升子序列: 最长公共子序列: 对于 O ( n 2 ) O(n^2) O ( n 2 ) 的做法就不再赘述了。 O ( n 2 ) O(n^2) O ( n 2 ) 的做法时空复杂度都太高了,所

    2024年01月17日
    浏览(25)
  • c++ 算法之动态规划—— dp 详解

    dp 是 c++ 之中一个简单而重要的算法,每一个 OIer 必备的基础算法,你知道它究竟是什么吗? 目录 一、简介         1.为什么不能贪心?         2.揭秘 dp   二、应用         1.定义         2.边界值         3.动态转移方程         4.结果         5.代码

    2024年04月09日
    浏览(40)
  • 动态规划dp详解(破解之道,就在其中)

    一.什么是动态规划 定义: 动态规划(英语:Dynamic programming,简称 DP),是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把 原问题分解为相对简单的子问题的方式 求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题

    2024年03月27日
    浏览(31)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包