最长递增子序列(LIS)

也是比较典型的动态规划问题。

第一种方法:将序列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");
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值