我们可以发现,求整个序列的最长上升子序列长度的子问题是“求以ak(k=1, 2, 3…N)为终点的最长上升子序列的长度”。
我们用max_len(k)表示以ak作为终点的最长上升子序列的长度。
初始状态:max_len(1)=1;
状态转移方程:max_len(k) = max{max_len(i) 1<=i < k 且 ai < ak且 k≠1 } + 1;
若没有符合条件的i,则max_len(k) = 1;
ak左边任何终点小于ak的子序列,加上ak自身后就能形成一个更长的上升子序列。
我们还使用了algorithm中的max_element函数,它的作用是返回容器中最大值。(min_element返回容器中最小值)
代码实现如下:
#include <iostream>
#include <algorithm>
using namespace std;
const int M =1000;
int a[M],max_len[M];
int main()
{
int n;
cin >>n;
for(int i=1; i<=n; i++) // 输入数据并把初始长度都设为1
{
cin >> a[i];
max_len[i]=1;
}
for(int i=2; i<=n; i++) //求以第i个数为终点的最长上升子序列的长度
{
for(int j=1; j<i; j++) //查看以第j个数为终点的最长上升子序列
{
if(a[i] > a[j])
max_len[i] = max(max_len[i], max_len[j]+1);
}
}
cout << *max_element(max_len+1, max_len+n+1); // 输出最大元素
return 0;
}
加一个nlogn的求lis的方法,主要就是利用了二分的思想。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 40010;
int a[MAXN];
bool cmp(int x, int y)
{
return x<y;
}
//int binary_search(int i)
//{
// int left,right,mid;
// left=0,right=len;
// while(left<right)
// {
// mid = left+(right-left)/2;
// if(ans[mid]>=arr[i])
// right=mid;
// else
// left=mid+1;
// }
// return left;
//}
int main()
{
int cas, n, ans;
scanf("%d",&cas);
while(cas--)
{
scanf("%d",&n);
ans = 0;
for(int i=0; i<n; i++)
{
scanf("%d",&a[i]);
int *p = lower_bound(a,a+ans,a[i],cmp);
if(p == a+ans)
ans++;
*p = a[i];
}
printf("%d\n",ans);
}
return 0;
}
最长公共子序列(LCS)
定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列。而最长公共子串(要求连续)和最长公共子序列是不同的。(百度百科)
在看了很多人写的博客后,我觉得还是好好理解状态转移方程,然后自己写一遍,debug一遍,体会更深。
(想写比这个时间复杂度低的算法,可以看下这个https://www.zhihu.com/question/21974937)。
杭电1159有练习题。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm> //最长公共子序列 hdu1159 已AC
using namespace std;
int c[1000][1000];
int main()
{
char a[1000],b[1000];
int len1,len2;
while(scanf("%s%s",a,b) != EOF)
{
memset(c,0,sizeof(c));
len1 = strlen(a);
len2 = strlen(b);
for(int i=1; i<=len1; i++)
{
for(int j=1; j<=len2; j++)
{
if(a[i-1] == b[j-1])
c[i][j] = c[i-1][j-1] + 1; //状态转移方程
else
c[i][j] = max(c[i][j-1],c[i-1][j]);
}
}
cout <<c[len1][len2]<<endl;
}
return 0;
}