最长序列算法
1. 最长公共序列(LCS)算法用c如何实现!
int **lcs_length(char p[],char q[],int **c,int **k,int m,int n)
{
int i,j;
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
{
if(p[i-1]==q[j-1])//如果两个字母相等的情况
{
c[i][j]=c[i-1][j-1]+1;
k[i][j]=1;
}
else
{
if(c[i-1][j]>=c[i][j-1])//两字母不等情况1
{
c[i][j]=c[i-1][j];
k[i][j]=2;
}
else//两字母不等情况2
{
c[i][j]=c[i][j-1];
k[i][j]=3;
}
}
}
}
return c,k;
}
输出代码
void print_lcs(int **k,char p[],int i,int j)
{
if(i==0||j==0)
return ;
if(k[i][j]==1)
{
print_lcs(k,p,i-1,j-1);//通过递归的方法按照输入的从头到尾的顺序输出LCS
cout<<p[i-1];
}
else if(k[i][j]==2)
print_lcs(k,p,i-1,j);
else
print_lcs(k,p,i,j-1);
}
2. 谁给个求最长公共子序列的算法
首先告诉你个网络账号叫pyx1997的人。他教会了我,现在让我来教会你。
我们来看一组数据:
40 100 50 60 70
好,让我们手动计算一下:
如果我们纯贪心的话:高个i变量直接从头到尾循环:到i=2时,就求得maxlen=2。i=5,maxlen被更新为3。但是我们看得出:最长不降子序列为40 50 60 70,maxlen=4。
为什么,为什么贪心会导致如此结果?那就是因为贪心童鞋的生理缺陷:目光短浅!
好了,让我们在重新审题。
此时因为我们的最长不降子序列同时要求“最长”和“不降”这两个方面,又因为我们的眼光要放长远,所以我们选择了用一个数组来记录以当前为起点的最长不降子序列。酱紫的话,我们就把这个大问题分成来若干个小问题。又因为如果我们顺退的话,我们不能确定到底是怎么样才算最长,前面的长度总是依赖于后面的长度。所以我们选择倒推。
a:原始数据的存放数组。
f:状态数组,即为以i(1<=i<=n)为起点的最长不降子序列的长度。不用设初值。
由于我不知道LZ使用的是什么语言,所以这里给出伪代码:
for i←n downto 1 //DP的次数
[maxlen←0 //将maxlen置空
for j←n downto i+1 //二重循环:比较i后的已知的最长不降子序列的长度。
if (f[j]>maxlen)&(a[i]>=a[j]) then maxlen←f[j] //求出最大值
f[i]←maxlen+1] //将最大值+1放入f[i]
然后,我们再将F数组扫描一遍,取最大值,即为答案。
如果要求序列的话,可以另开一个存放下一个值的数组next,然后再循环的最后加上一句next[i]←j
算法描述完毕。具体的细节请自行调试。本人打的很辛苦,望lz给分。
3. 最长公共子序列算法
可以用后缀数组搞。
可以看下这个
http://www.cnblogs.com/looker_acm/archive/2010/07/18/1780176.html
4. 最长 公共子序列问题(算法分析 C++)
#include <iostream>
#include <string>
using namespace std;
//主函数
int main()
{
int m,n;
char *x,*y;
int **b,**c;
void LCSLength(int m,int n,char *y,char *x,int **c,int **b);
void LCS(int i,int j,char *x,int**b);
cout<<"请输入两个序列的长度:"<<endl;
cin>>m>>n;
x=new char[m];
y=new char[n];
cout<<"请输入两个序列:"<<endl;
cin>>x>>y;
b=new int *[m + 1]; // 注意这里,原式没有+1
for (int i=0;i<=m;i++)
b[i]=new int[n + 1]; // 注意这里,原式没有+1
c=new int *[m + 1];
for (int j=0;j<=m;j++)
c[j]=new int[n + 1]; // 注意这里,原式没有+1
LCSLength(m,n,x,y,c,b);
cout<<"最长公共子序列的元素个数为"<<c[m][n]<<endl;
cout<<"该序列为:";
LCS(m,n,x,b); //注意后面的内容是清理,暂时先跳过去,你先搞定主程序先
/* delete []x;
delete []y;
for(int k=0;k<=m;k++)
delete []b[k];
delete []b;
for(int h=0;h<=m;h++)
delete []c[h];
delete []c;
*/
return 0;
}
//计算最优值
void LCSLength(int m,int n,char *y,char *x,int **c,int **b)
{
int i,j;
for(i=1;i<=m;i++)c[i][0]=0;
for(j=0;j<=n;j++)c[0][j]=0;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
{
if(x[i]==y[j]){c[i][j]=c[i-1][j-1]+1;b[i][j]=1;}
else if(c[i-1][j]>=c[i][j-1]){c[i][j]=c[i-1][j];b[i][j]=2;}
else {c[i][j]=c[i][j-1];b[i][j]=3;}
}
}
//构造最长公共子序列
void LCS(int i,int j,char *x,int**b)
{
if(i==0||j==0)return;
if(b[i][j]==1){LCS(i-1,j-1,x,b);cout<<x[i];}
else if(b[i][j]==2)LCS(i-1,j,x,b);
else LCS(i,j-1,x,b);
}
5. C语言求最长子序列
下面是你的代码修改过后的结果,改过的地方都有注释,另有测试样例。
#include <stdio.h>
/*
5
5
-2 5 4 -7 3
最长子序列:9
4
-2 -3 8 -7
最长子序列:8
3
-2 -2 7
最长子序列:7
2
-1 5
最长子序列:5
1
-2
最长子序列:0
Process returned 0 (0x0) execution time : 30.999 s
Press any key to continue.
*/
int main() {
int count, i, k, a[100] = {0}, b[10000] = {0}, n, num, max = 0, q, m, j;
scanf("%d", &n);
for (count = 0; count < n; count++) {
scanf("%d", &num);
for (i = 0; i < num; i++) scanf("%d", &a[i]);
k = 0;
for (i = 0; i < num; i++)
for (q = 1; q < num + 1; q++) {
for (m = i; (m < i + q) && (m < num); m++) //在这里再加一个判断条件(m < num),
b[k] += a[m];
k++;
}
j = k - 1;
max = 0; //如果全部都是负数的话,结果应该是0,即一个都不选
for (; j >= 0; j--)
if (max < b[j]) max = b[j];
printf("最长子序列:%d\n", max);
max = 0;
for (i = 0; i < 10000; i++) b[i] = 0;
}
return 0;
}
6. O(nlogn)最长递增子序列算法,如何输出所求子序列
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
if (nums.size() == 0) return 0;
vector<int> dp(nums.size(), INT_MAX);
vector<int> pos(nums.size(), INT_MAX);
for (int i = 0; i < nums.size(); i++){
pos[i] = lower_bound(dp.begin(), dp.end(), nums[i]) - dp.begin();
*lower_bound(dp.begin(), dp.end(), nums[i]) = nums[i];
}
int max_n = lower_bound(dp.begin(), dp.end(), INT_MAX) - dp.begin();
vector<int> res(max_n, -1);
int j = max_n - 1;
for (int i = nums.size() - 1; i >= 0; --i){
if (j < 0) break;
if (j == pos[i]){
res[j--] = nums[i];
}
}
for (auto x : res)
cout << x << " ";
cout << endl;
return max_n;
}
};
int main() {
Solution s;
vector<int> nums = {12,2, 34, 4, 5, 6, 7, 8, 9, 0};
cout << s.lengthOfLIS(nums) << endl;
return 0;
}
7. 最长子序列算法的程序 要求用C语言!
有两种算法复杂度为O(n*logn)和O(n^2)
O(n^2)算法分析如下: (a[1]...a[n] 存的都是输入的数)
1、对于a[n]来说,由于它是最后一个数,所以当从a[n]开始查找时,只存在长度为1的不下降子序列;
2、若从a[n-1]开始查找,则存在下面的两种可能性:
(1)若a[n-1] < a[n] 则存在长度为2的不下降子序列 a[n-1],a[n].
(2)若a[n-1] > a[n] 则存在长度为1的不下降子序列 a[n-1]或者a[n]。
3、一般若从a[t]开始,此时最长不下降子序列应该是按下列方法求出的:
在a[t+1],a[t+2],...a[n]中,找出一个比a[t]大的且最长的不下降子序列,作为它的后继。
4、为算法上的需要,定义一个数组:
d:array [1..n,1..3] of integer;
d[t,1]表示a[t]
d[t,2]表示从i位置到达n的最长不下降子序列的长度
d[t,3]表示从i位置开始最长不下降子序列的下一个位置
最长不下降子序列的O(n*logn)算法分析如下:
先回顾经典的O(n^2)的动态规划算法,设A[t]表示序列中的第t个数,F[t]表示从1到t这一段中以t结尾的最长上升子序列的长度,初始时设F[t] = 0(t = 1, 2, ..., len(A))。则有动态规划方程:F[t] = max{1, F[j] + 1} (j = 1, 2, ..., t - 1, 且A[j] < A[t])。
现在,我们仔细考虑计算F[t]时的情况。假设有两个元素A[x]和A[y],满足
(1)x < y < t (2)A[x] < A[y] < A[t] (3)F[x] = F[y]
此时,选择F[x]和选择F[y]都可以得到同样的F[t]值,那么,在最长上升子序列的这个位置中,应该选择A[x]还是应该选择A[y]呢?
很明显,选择A[x]比选择A[y]要好。因为由于条件(2),在A[x+1] ... A[t-1]这一段中,如果存在A[z],A[x] < A[z] < a[y],则与选择A[y]相比,将会得到更长的上升子序列。
再根据条件(3),我们会得到一个启示:根据F[]的值进行分类。对于F[]的每一个取值k,我们只需要保留满足F[t] = k的所有A[t]中的最小值。设D[k]记录这个值,即D[k] = min{A[t]} (F[t] = k)。
注意到D[]的两个特点:
(1) D[k]的值是在整个计算过程中是单调不上升的。
(2) D[]的值是有序的,即D[1] < D[2] < D[3] < ... < D[n]。
利用D[],我们可以得到另外一种计算最长上升子序列长度的方法。设当前已经求出的最长上升子序列长度为len。先判断A[t]与D[len]。若A [t] > D[len],则将A[t]接在D[len]后将得到一个更长的上升子序列,len = len + 1, D[len] = A[t];否则,在D[1]..D[len]中,找到最大的j,满足D[j] < A[t]。令k = j + 1,则有D[j] < A[t] <= D[k],将A[t]接在D[j]后将得到一个更长的上升子序列,同时更新D[k] = A[t]。最后,len即为所要求的最长上升子序列的长度。
在上述算法中,若使用朴素的顺序查找在D[1]..D[len]查找,由于共有O(n)个元素需要计算,每次计算时的复杂度是O(n),则整个算法的时间复杂度为O(n^2),与原来的算法相比没有任何进步。但是由于D[]的特点(2),我们在D[]中查找时,可以使用二分查找高效地完成,则整个算法的时间复杂度下降为O(nlogn),有了非常显着的提高。需要注意的是,D[]在算法结束后记录的并不是一个符合题意的最长上升子序列!
这个算法还可以扩展到整个最长子序列系列问题,整个算法的难点在于二分查找的设计,需要非常小心注意。
8. 最长上升子序列
最长上升子序列问题是各类信息学竞赛中的常见题型,也常常用来做介绍动态规划算法的引例,笔者接下来将会对POJ上出现过的这类题目做一个总结,并介绍解决LIS问题的两个常用
算法(n^2)和(nlogn).
问题描述:给出一个序列a1,a2,a3,a4,a5,a6,a7....an,求它的一个子序列(设为s1,s2,...sn),使得这个子序列满足这样的性质,s1<s2<s3<...<sn并且这个子序列的长度最长。输出这个最长的长度。(为了简化该类问题,我们将诸如最长下降子序列及最长不上升子序列等问题都看成同一个问题,其实仔细思考就会发现,这其实只是<符号定义上的问题,并不影响问题的实质)
例如有一个序列:1 7 3 5 9 4 8,它的最长上升子序列就是 1 3 4 8 长度为4.
算法1(n^2):我们依次遍历整个序列,每一次求出从第一个数到当前这个数的最长上升子序列,直至遍历到最后一个数字为止,然后再取dp数组里最大的那个即为整个序列的最长上升子序列。我们用dp[i]来存放序列1-i的最长上升子序列的长度,那么dp[i]=max(dp[j])+1,(j∈[1, i-1]); 显然dp[1]=1,我们从i=2开始遍历后面的元素即可。
9. c++中怎么求数组中最长的递增序列
例如数组 data[]={-9,0,-3,-5,-1,-2}
最后求得最长递增子序列的长度为 3 (-9,-3,-1),当然还有好几种同种长度的递增子序列的组合
核心算法:
C++表示算法如下:
// 求数组中最长递增子序列
int Array::Max_Length_GoUp_stack(int *data,unsigned int const length)
{
// 异常输入,ITJOB
if(data == NULL || length == 0)
{
cout<<"输入异常 Max_Length_GoUp"<<endl; return="" 0;="" }="" 正常输入="" else="" {="" 核心算法,用工具栈去解决问题="" stack * S = new stack;
S->push(0);
unsigned int now = 0;
unsigned int result = 1;
while(S->empty() == false)
{
// 可以进栈
now ++;
if(now < length)
{
while(now < length)
{
if(data[now] > data[S->top()])
{
S->push(now);
}
now++;
}
// 更新结果
if(S->size() > result)
result = S->size();
}
// 出栈操作
else{
now = S->top();
S->pop();
}
}
// 返回结果
return result;
}
}
10. 求最长单调序列C++算法
你这个例子不对吧?300 250 275 252 200 138 245,输出应该是
275 252 200 138吧?我编的算法(连续两个相等的不算增也不算减):
#include<iostream>
using namespace std;
int main()
{
int num[200],n,len,maxlen,begin,end,mxbegin,mxend,i,increase;
cout<<"输入序列的总长度:"<<endl;
cin>>n;
cout<<"输入各个数:"<<endl;
for(i=0;i<n;i++)
cin>>num[i];
begin=end=len=maxlen=mxbegin=mxend=0;
if(num[1]>num[0])
increase=1;
else
increase=0;
for(i=1;i<n;i++)
{
if(num[i]>num[i-1] && increase==1)
end=i;
else if(num[i]<num[i-1] && increase==0)
end=i;
else if(num[i]>num[i-1] && increase==0)
{
len=end-begin+1;
if(len>maxlen)
{
maxlen=len;
mxbegin=begin;
mxend=end;
}
begin=i-1;
end=i;
increase=1;
}
else if(num[i]<num[i-1] && increase==1)
{
len=end-begin+1;
if(len>maxlen)
{
maxlen=len;
mxbegin=begin;
mxend=end;
}
begin=i-1;
end=i;
increase=0;
}
else
{
len=end-begin+1;
if(len>maxlen)
{
maxlen=len;
mxbegin=begin;
mxend=end;
}
begin=end=i;
increase=0;
}
}
if(end==n-1 && end-begin+1>maxlen)
{
maxlen=end-begin+1;
mxbegin=begin;
mxend=end;
}
for(i=mxbegin;i<=mxend;i++)
cout<<num[i]<<" ";
cout<<endl;
return 0;
}