线性模型
一个序列、一串数字或者是一个字符串等等
对于“环”,我们可以将其展开形成“非环”,通常可以待操作的串复制一遍接在后面,形成双倍长度的串来表示原先的环。
例题:
- 最大子串和
- 最长上升子序列(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。
本文探讨线性模型在动态规划中的应用,包括最大子串和、最长上升子序列(LIS)和矩阵连乘等。介绍了如何通过将环展开成非环处理问题,并提供了一种时间复杂度和空间复杂度均为O(n)的解决方案。同时,文章讲解了最大上升子序列的两种方法,一种是O(n^2)的动态规划实现,另一种是结合贪心和二分查找的O(n log n)方法,这种方法能构建接纳能力最强的序列。
2万+

被折叠的 条评论
为什么被折叠?



