Dynamic Programming 学习笔记(二) LIS vs LCS

 

LIS (Longest Increasing Subsequence) 最长上升子序列

题目:给出一个序列a1,a2,a3,a4,a5,a6,a7….an,求它的一个子序列(设为s1,s2,…sn),使得这个子序列满足这样的性质,s1<s2<s3<…<sn并且这个子序列的长度最长。输出这个最长的长度。

LCS (Longest Common Subsequence) 最长公共子序列。

题目:一个数列 S,如果其分别是两个或多个已知数列的子序列,且是最长的序列,则S 称为已知序列的最长公共子序列。

LIS与LCS都是典型的DP问题。

 

对于LIS,有两种基本的算法。

1.  依次遍历整个序列,每一次求出从第一个数到当前这个数的最长上升子序列,直至遍历到最后一个数字为止,然后再取dp数组里最大的那个即为整个序列的最长上升子序列。我们用dp[i]来存放序列1-i的最长上升子序列的长度,那么dp[i]=max(dp[j])+1,(j∈[1, i-1]); 显然dp[1]=1,我们从i=2开始遍历后面的元素即可。O(N^2)复杂度。

int LIS(int arr[1000], int n)
{
	for(int i=1; i<=n; ++i)
		dp[i] = 0;
	int max;
	dp[1] = 1;
	for(int i = 2; i <= n; ++i)
	{
		for(int j=1; j < i; ++j)
		{
			if(arr[i] > arr[j] && dp[j] + 1 > dp[i])
				dp[i] = dp[j] + 1;
		}
		if (dp[i] > max)
			max = dp[i];
	}

	return max;
} 

 

2.  用f[k]表示长度为k的上升子序列最后一个数最小是多少。易知数组f是递增的。读到一个新的数x后,找到某个i使得x>f[i]且x<=f[i+1],于是用x去更新f[i+1];特别地,如果所有的f[i]都小于x,则增加f的长度。f的长度即为所求。由于f是递增的,因此可以采用二分查找,时间复杂度为O(nlgn)。

 

int bSearch(int num, int k)  
{  
    int low=1, high=k;  
    while(low<=high)  
    {  
        int mid=(low+high)/2;  
        if(num>=b[mid])  
            low=mid+1;  
        else   
            high=mid-1;  
    }  
    return low;  
}  
 
int LIS_bak()
{
	int low = 1, high = n;
	int k = 1;
	b[1] = p[1];
	for(int i=2; i<=n; ++i)
	{
		if(p[i]>=b[k])
			b[++k] = p[i];
		else
		{
			int pos = bSearch(p[i], k);
			b[pos] = p[i];
		}
	}
	return k;
} 


而对于LCS

子问题的递归结构为

分析:设序列X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的一个最长公共子序列Z=<z1, z2, …, zk>,则:

1.  若xm=yn,则zk=xm=yn且Zk-1是Xm-1和Yn-1的最长公共子序列;

2.  若xm≠yn且zk≠xm 则Z是Xm-1和Y的最长公共子序列;

3.  若xm≠yn且zk≠yn ,则Z是X和Yn-1的最长公共子序列。

其中Xm-1=<x1, x2, …, xm-1>,Yn-1=<y1, y2, …, yn-1>,Zk-1=<z1, z2, …, zk-1>。

用c[i,j]记录序列Xi和Yj的最长公共子序列的长度。其中Xi=<x1, x2, …, xi>,Yj=<y1, y2, …, yj>。当i=0或j=0时,空序列是Xi和Yj的最长公共子序列,故c[i,j]=0。

下图能够说明这个问题。

 

注意:最长公共子串(Longest CommonSubstring)和最长公共子序列(LongestCommon Subsequence, LCS)的区别:子串(Substring)是串的一个连续的部分,子序列(Subsequence)则是从不改变序列的顺序,而从序列中去掉任意的元素而获得的新序列

  

参考文献:

http://www.wutianqi.com/?p=1850

http://www.matrix67.com/blog/archives/112

http://blog.csdn.net/v_july_v/article/details/6695482

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值