问题描述:
给定一个长度为N的数组,找出一个最长的单调自增子序列(不一定连续,但是顺序不能乱)。例如:给定一个长度为6的数组A{5, 6, 7, 1, 2, 8},则其最长的单调递增子序列为{5,6,7,8},长度为4.
方法一:这个方法是我用java实现的,利用java里 容器,从头开始遍历数组,每遍历一个元素,需要进行两步操作:第一、创建一个新的LinkedList,并将这个元素放进去;第二、将这个元素分别与之前元素的各个递增队列的最大值比较,如果大于之前递增队列的最大值,则将其存储到相应的LinkedList里。最后的结果是:一共需要n个队列,这n个队列里存储的是所有的递增子序列,找到最大的即可。
代码如下:
public class MaxLenSubSeq {
//最长递增子序列
public int num[] =new int[100];
@SuppressWarnings("unchecked")
public LinkedList<Integer> maxLenSubSeq(int[] seq){
if(seq==null||seq.length==0){
return null;
}
List<LinkedList> list = new ArrayList<LinkedList>();
int len = seq.length;
for(int i=0;i<len;i++){
num[i]=1;
LinkedList<Integer> llist= new LinkedList<Integer>();
llist.addFirst((seq[i]));
list.add(llist);
for(int j=0;j<i;j++){
if(seq[i]>(Integer)list.get(j).getFirst()){
num[j]= num[j]+1;
list.get(j).addFirst(seq[i]);
}
}
}
int maxtemp =0;
int k =-1;
for(int i=0;i<num.length;i++){
if(num[i]>maxtemp){
maxtemp = num[i];
k = i;
}
}
return list.get(k);
}
}
方法二、利用一般动态规划的思路
设置辅助数组Len[i],表示对于序列以A[i]为结尾的子序列的最长递增子序列的长度,则序列的最长递增子序列为max{Len[i]}(0<i<n);
b[i]的状态转移方程为:
b[i] = 1当i ==1;
b[i] = max{b[k]+1}(0<i<n;1<=k<i)
代码实现:
/**
* Seq为序列
* n为序列长度
* */
public int maxLenAsSubSeq(int[] Seq,int n){
int[] Len = new int[n];
int max =0;
Len[0] =1;
for(int i=1;i<n;i++){
Len[i] =1;
for(int j=0;j<i;j++){
//System.out.println(Seq[i]+" "+Seq[j]);
if((Seq[i]>Seq[j])&&(Len[j]+1)>Len[i]){
Len[i] = Len[j]+1;
}
}
if(max<Len[i]){
max =Len[i];
}
}
return max;
}
当然,最长递增子序列的求法还有其他:比如:利用最大公共子序列。此方法的具体实现,下午更新,敬请关注
继续方法三:
最大公共子序列方法:
因为需要求解A序列的最大递增子序列,我们可以将序列A进行排序,排序后的序列A'单调递增,根据最大公共子序列的性质,我们把A和A’的最大公共子序列求出来,其实就是A的最大递增子序列,因为A’递增,又满足最大公共。
代码实现:
//排序
public int[] sort(int[] num){
int[] numtemp = num;
int numlen = numtemp.length;
for(int i=0;i<numlen;i++){
for(int j=i;j<numlen;j++){
if(numtemp[i]>numtemp[j]){
int temp = numtemp[i];
numtemp[i] = numtemp[j];
numtemp[j] =temp;
}
}
}
return numtemp;
}
/**
* 最长公共子序列
* seq1:第一个序列
* seq2:第二个序列
* */
public int LongComSubSeq(int[] seq1,int[] seq2){
if(seq1==null||seq1.length==0||seq2==null||seq2.length==0){
return -1;
}
int len1 = seq1.length+1;
int len2 = seq2.length+1;
//存放公共子串的长度
int[][] LCSLen = new int[len1][len2];
//存放
int[][] LCSDrec = new int[len1][len2];
//接下来三个循环为初始化
for(int i=0;i<len1;i++){
LCSLen[i][0] = 0;
}
for(int j=0;j<len2;j++){
LCSLen[0][j] = 0;
}
for(int i=0;i<len1;i++){
for(int j=0;j<len2;j++){
LCSDrec[i][j] =0;
}
}
for(int i=1;i<len1;i++){
for(int j=1;j<len2;j++){
if(seq1[i-1] == seq2[j-1]){
//System.out.println("序列值seq1:"+seq1[i-1]);
// System.out.println("序列值seq2:"+seq2[j-1]);
LCSLen[i][j] = LCSLen[i-1][j-1]+1;
// System.out.println("序列长度:"+LCSLen[i][j]);
LCSDrec[i][j] = 1;
}else if(LCSLen[i-1][j]>LCSLen[i][j-1]){
LCSLen[i][j] = LCSLen[i-1][j];
LCSDrec[i][j] = 2;
}else {
LCSLen[i][j] =LCSLen[i][j-1];
LCSDrec[i][j] = 3;
}
}
}
LCSPrint(LCSDrec,seq1,len1-1,len2-1);
return LCSLen[len1-1][len2-1];
}
//最长公共子序列输出函数
public void LCSPrint(int[][] LCSDrec,int[] seq1,int len1,int len2){
if(LCSDrec==null||seq1==null||len1<=0||len2<=0){
return;
}
if(LCSDrec[len1][len2]==1){
System.out.println(" "+seq1[len1-1]);
LCSPrint(LCSDrec,seq1,len1-1,len2-1);
}else if(LCSDrec[len1][len2]==2){
LCSPrint(LCSDrec,seq1,len1-1,len2);
}else{
LCSPrint(LCSDrec,seq1,len1,len2-1);
}
}
转载于:https://blog.51cto.com/kisuntech/1344369