最长上升子序列 最长公共子序列
来源:互联网 发布:淘宝商家被骗了怎么办 编辑:程序博客网 时间:2024/06/17 08:20
最长上升子序列为DP问题,所以我们可以用DP来解决。它有两种算法,首先介绍一下
时间复杂度为O(n^2):
递推关系:dp[i]={1,d[j]+1|j<i且aj<ai}
dp[]:=以ai为末尾的最长上升子序列的长度
而以ai结尾的上升子序列是:
(1)只包含ai的子序列
(2)在满足j<i
并且aj<a
i的以aj为结尾的上升子列末尾,追加上ai后得到的子序列。
我们依次遍历整个序列,每一次求出从第一个数到当前这个数的最长上升子序列,直至遍历到最后一个数字为止,然后再取dp数组里最大的那个即为整个序列的最长上升子序列。我们用dp[i]来存放序列1-i的最长上升子序列的长度,那么dp[i]=max(dp[j])+1,(j∈[1, i-1]); 显然dp[1]=1,我们从i=2开始遍历后面的元素即可。
代码如下:
#include <iostream>#include <algorithm>#include <stdio.h>#include <cstring>using namespace std;const int N=1e6;int n,a[N],dp[N];void f() //求最长上升子序列{ int ans=0; for(int i=1;i<=n;i++) { dp[i]=1; for(int j=1;j<=n;j++) if(a[j]<a[i]) dp[i]=max(dp[i],dp[j]+1); ans=max(dp[i],ans); } cout<<ans<<endl;}int main(){ memset(a,0,sizeof(a)); memset(dp,0,sizeof(dp)); cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; f(); return 0;}
时间复杂度为O(nlogn):
必需满足条件:dp数列中除INF之外是单调递增的
最开始初始话dp为inf。然后由前向后逐个考虑数列的元素,对于每个aj,如果i=0或者dp[i-1]<aj
的话,就用dp[i]=min(dp[i],aj)进行更新,最终找出使得dp[i]
#include <iostream>#include <algorithm>#include <stdio.h>#include <cstring>using namespace std;const int N=1e6;const int inf=0x3f3f3f3f;int n,a[N],dp[N];void f() //lower_bound()为二分函数,详情请见二分法那篇博客{ int ans=0; for(int i=1;i<=n;i++) { *lower_bound(dp+1,dp+n+1,a[i])=a[i]; } cout<<lower_bound(dp+1,dp+n+1,inf)-dp-1<<endl;}int main(){ memset(a,0,sizeof(a)); memset(dp,inf,sizeof(dp)); cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; f(); return 0;}
另一种二分:
#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>#define MAXN 40005using namespace std;int arr[MAXN],ans[MAXN],len;int main(){ int n; int T; cin>>T; while(T--) { cin>>n; for(int i=1; i<=n; ++i) scanf("%d",&arr[i]); ans[1] = arr[1]; len=1; for(int i=2; i<=n; ++i) { if(arr[i]>ans[len]) ans[++len]=arr[i]; else { int pos=lower_bound(ans,ans+len,arr[i])-ans; ans[pos] = arr[i]; } } cout<<len<<endl; } return 0;}
最长公共子序列
引进一个二维数组dp[][],用dp[i][j]记录s[i]与t[j] 的LCS 的长度.
我们是自底向上进行递推计算,那么在计算dp[i,j]之前,dp[i-1][j-1],dp[i-1][j]与dp[i][j-1]均已计算出来。此时我们根据s[i] = t[j]还是s[i] != t[j],就可以计算出dp[i][j]。
问题的递归式写成:
回溯输出最长公共子序列过程:
首先做初始化。将c[0][i]和从c[i][0]初始化为0,然后一行一行的填表。
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>using namespace std;const int N=1e6;int dp[500][500];char s[1000],t[1000];int n,m;void f(){ for(int i=0;i<n;i++) for(int j=0;j<m;j++) if(s[i]==t[j]) dp[i+1][j+1]=dp[i][j]+1; else dp[i+1][j+1]=max(dp[i][j+1],dp[i+1][j]); cout<<dp[n][m]<<endl;}int main(){ scanf("%s%s",s,t); n=strlen(s); m=strlen(t); f(); return 0;}
- 最长公共上升子序列
- 最长公共上升子序列
- 最长上升公共子序列
- 最长公共上升子序列
- 最长公共上升子序列
- 最长公共上升子序列
- 最长公共上升子序列
- 最长公共上升子序列
- 最长公共上升子序列
- 最长公共上升子序列
- 最长公共子上升序列
- 最长公共上升子序列
- 最长公共上升子序列
- 最长上升子序列、最长公共上升子序列
- 最长公共子序列、上升子序列、最长上升子序列、最长公共子串
- 最长公共子序列,最长上升公共子序列
- 最长上升子序列(LIS)&最长公共子序列(LCS)
- 最长上升子序列 最长公共子序列
- 对象转化为json
- Android Timer 定时器 与handler的配合
- 正则表达式
- IO流——自定义字节流的缓冲区
- UE4 天空盒制作
- 最长上升子序列 最长公共子序列
- 剑指offer-丑数
- tcpdump
- Java四大特征(抽象、封装、继承、多态)
- 安卓实现按返回键回到桌面以及再一次按返回键退出应用
- 高数基础4-导数与微分
- 深刻理解引用、const引用、右值引用的本质
- 调整数组顺序使奇数位于偶数前面
- JNI调用c基本用法