也是比较典型的动态规划问题。
第一种方法:将序列A排序得到一个新的序列A' ,然后求解A和A'的最长公共子序列即可
C++代码:
#include "stdafx.h"
#include<iostream>
#include<algorithm>
using namespace std;
void init(int *copy,int *seq,int len)
{
for(int i=0;i<len;i++)
copy[i] = seq[i];
}
int Max(int a,int b)
{
return a>b?a:b;
}
void lcs(int *seq,int *copy,int **maxlen,int len)
{
for(int i=0;i<len+1;i++)//初始化第0行和列
{
maxlen[0][i] = 0;
maxlen[i][0] = 0;
}
for(int i=1;i<len+1;i++)//求解lcs的过程
{
for(int j=1;j<len+1;j++)
{
if(seq[i-1] == copy[j-1])
{
maxlen[i][j] = maxlen[i-1][j-1]+1;
}
else
{
maxlen[i][j] = Max(maxlen[i-1][j],maxlen[i][j-1]);
}
}
}
}
void printPath(int **maxlen,int *seq,int *copy,int row,int col)//递归输出一个最长递增子序列
{
if(row == 0||col == 0)
return;
if(seq[row-1] == copy[col-1])
{
printPath(maxlen,seq,copy,row-1,col-1);
cout<<seq[row-1]<<" ";//输出要放后面,不然输出的是递减子序列
}else if(maxlen[row-1][col]>maxlen[row][col-1])
{
printPath(maxlen,seq,copy,row-1,col);
}else{
printPath(maxlen,seq,copy,row,col-1);
}
}
int main()
{
int seq[] = {1,3,4,2,7,5,9};
int len = sizeof(seq)/sizeof(int);
int *copy = (int *)malloc(sizeof(int)*len);
init(copy,seq,len);//用seq数组,对copy初始化
sort(copy,copy+len);//对copy排序
//多申请一维,第0行和列都初始化为0。maxlen[i][j]表示seq前i个字符和copy前j个字符中最长公共子序列的长度
int **maxlen =(int **)malloc(sizeof(int *)*(len+1));
for(int i=0;i<len+1;i++)
{
maxlen[i] = (int *)malloc(sizeof(int)*(len+1));
}
lcs(seq,copy,maxlen,len);//求解最长公共子序列的过程
cout<<maxlen[len][len]<<endl;//返回最长公共子序列的长度
printPath(maxlen,seq,copy,len,len);
getchar();
return 0;
}
第二种方法:maxlen[i]表示以A[i]结尾的最长序列,如果A[i]后的某个A[j]>A[i],那么原来以A[i]结尾的最长序列,加上A[j]就得到了长度为maxlen[i]+1的以A[j]结尾的子序列。
所以求解maxlen[j]的方法,就是在i<j中的每一个A[i],找出每一个A[j]>A[i]中的i,求的maxlen[i]+1中最大的那个,用来更新maxlen[j].如果所有A[i]都不小于A[j],那么maxlen[j]就等于1,即,单独一个A[j]构成的序列
Java代码如下,这个以前用Java写的
import java.util.Stack;
public class LIS {
public static void getLIS(int seq[],int maxlen[])//产生lis的过程
{
for(int i=0;i<maxlen.length;i++)
{
maxlen[i]=1;
for(int j=i-1;j>=0;j--)
{
if(seq[i]>seq[j] && maxlen[j]>=maxlen[i])
{
maxlen[i] = maxlen[j]+1;
}
}
}
}
public static void printPath(int seq[],int maxlen[],int len)//输出一个lis
{
Stack<Integer> ss = new Stack<Integer>();//存储节点
if(len == 0) return;
int maxLen = 0;
int maxIndex = 0;
for(int i=0;i<len;i++)//首先找到最长lis的最后一个数字的索引
{
if(maxlen[i]>maxLen)
{
maxLen = maxlen[i];//当前的最长的lis长度
maxIndex = i;
}
}
ss.push(seq[maxIndex]);//lis的最后一个字母入栈,maxIndex表示Lis的最后一个数字在seq中的索引
for(int j=0;j<maxLen-1;j++)//总共还要找到maxlen-1个数字
{
int max = 0;
int tmp = 0;//需要在maxIndex之前找到一个数字,使得其lis最长
for(int i=0;i<maxIndex;i++)
{
if(maxlen[i]>max)
{
max = maxlen[i];
tmp = i;
}
}
maxIndex = tmp;//更新maxIndex
ss.push(seq[maxIndex]);
}
while(!ss.empty())//输出stack
{
System.out.print(ss.pop()+" ");
}
}
public static void main(String args[])
{
int seq[]= {1,3,4,2,7,5,9};
int maxlen[] = new int[seq.length];
//int path[] = new int[seq.length];
getLIS(seq,maxlen);
for(int i=0;i<maxlen.length;i++)
{
System.out.print(maxlen[i]+"\t");
}
System.out.println();
printPath(seq,maxlen,maxlen.length);
System.out.println("Game Over");
}
}