[动态规划]线性(一维/串、环)模型

本文探讨线性模型在动态规划中的应用,包括最大子串和、最长上升子序列(LIS)和矩阵连乘等。介绍了如何通过将环展开成非环处理问题,并提供了一种时间复杂度和空间复杂度均为O(n)的解决方案。同时,文章讲解了最大上升子序列的两种方法,一种是O(n^2)的动态规划实现,另一种是结合贪心和二分查找的O(n log n)方法,这种方法能构建接纳能力最强的序列。

线性模型

一个序列、一串数字或者是一个字符串等等
对于“环”,我们可以将其展开形成“非环”,通常可以待操作的串复制一遍接在后面,形成双倍长度的串来表示原先的环。
例题:

  • 最大子串和
  • 最长上升子序列(LIS)
  • 矩阵连乘


  • 最大子串和

题目大意:
           给出一个整数串a,a[i]表示其中的第i个整数,a[i]有正有负,求其中一个连续子串,使得该子串的和最大。
状态表示:
           f[i]表示以第i个整数结尾的子串所能得到的最大和。
状态转移方程:

           f[i]=max{f[i-1]+a[i] , a[i]}
边界条件:
f[0]=a[0]

实现略, 时间复杂度和空间复杂度都是O(n)




  • 最大上升子序列
题目大意:
           给出一个整数串a,a[i]表示其中的第i个整数,的求其中最长的一个子序列,使得该子序列是递增的。
           子序列的定义:
           设a的长度为n,对于一个长度为m(m<=n)的串b,对于任意i(0<i<m-1)有0<b[i]<n,且b[i]<b[i+1]。
则a[b[0]],a[b[1]],……,a[b[m]],是a的一个子序列。简单来说子序列就是元素可不连续的子串。
状态表示:
f[i]表示以第i个数为结尾的子序列的最大长度。
状态转移方程:

f[i]=max{f[j]+1,f[i]}(0<=j<i && a[j]<a[i])

边界条件:

见代码


实现一, 时间复杂度和空间复杂度都是O(n^2)

#include<iostream>
using namespace std;
const int N = 100;
int main()
{
	char s1[N], s2[N];
	int f[N][N];
	int i, j;
	scanf("%s", s1);
	scanf("%s", s2);

	int l1 = strlen(s1);
	int l2 = strlen(s2);
	for(i=0;i<=l1;i++)
		f[l1][0] = 0;  //边界条件
	for(i=0;i<=l2;i++)
		f[0][l2] = 0;  //边界条件
	for(i=1;i<=l1;i++)
	{
		for(j=1;j<=l2;j++)
		{
			if(s1[i-1]==s2[j-1])
				f[i][j] = f[i-1][j-1] + 1;
			else
				f[i][j] = max(f[i-1][j], f[i][j-1]);
		}
	}
	printf("%d\n", f[l1][l2]);

}

实现二, 时间复杂度 O(n logn)

贪心+二分查找:
开辟一个栈,每次取栈顶元素s和读到的元素a做比较,如果a>s,  则加入栈;如果a<s,则二分查找栈中的比a大的第1个数,并替换。  最后序列长度为栈的长度。  
这也是很好理解的,对x和y,如果x<y且E[y]<E[x],用E[x]替换  E[y],此时的最长序列长度没有改变但序列Q的''潜力''增大, 即构建一个接纳能力最强的序列。

这里就要运用二分查找了,当查找元素T结束时, l>r, 而在在这个递增序列中, E[l]=>T>=E[r], 这样可以快速的返回该序列中小于T的最大值或大于T的最小值。


to be continued。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值