尝试解释LIS(最长递增子序列)的一种动态规划算法

最长上升子序列就是求给定序列的最长的递增序列,其中不要求序列的元素在原序列中保持连续。

为了方便理解,可以举个例子:

inta[] = {0,2,1,5,3,6,4,8,9,7}(数组下标从1开始)的一个最长的子序列1,3,4,7,9。

利用动态规划的思想,可以方便的求取这个解。

为了方便解释,我们定义dp(n)为长度为1至下标为n的最长子序列的长度(数组下标假设从1开始),{a[1],a[2],..,a[n]}为dp(n)对应的序列。

为了和程序对应,我采取自底向上的方式进行解释。

1.显然对于序列dp(1) 对应的{2}来说,最长递增子序列的长度就是1;

2.对于序列dp(2) 对应的{2,1},我们首先比较a[2]和a[1]大小,

若a[2]>a[1],显然此时的{a[1],a[2]}是一个最长子序列,故dp(2) = dp(1)+1=2,

若a[2]<=a[1], 此时一个最长子序列的长度仍然为1,即dp(2) = 1;

在我们的例子中a[2]= 1 <a[1]=2,故dp(2)=1;

3.那么对于包含三个数的序列dp(3)对应的{2,1,5}来说呢

此时a[3]要和a[1], a[2]进行比较,此时可能会出现这种情况

a[3]>a[1],由于子序列可以是不连续的,故{a[1],a[3]}可以是一个子序列,dp[3]=dp[1]+1

a[3]>a[2],说明以a[2]为末端的子序列(可以不连续哦)+a[3]能形成一个新的子序列,此时要给dp[3]赋值,

那么dp[3]是等于dp[1]+1还是dp[2]+1呢

既然我们要求最长子序列,那么就要让dp[3]=max{dp[2],dp[1]}+1

若a[3]<a[1],a[3]<a[2]

还是令dp[3] = 1;

例子中a[3]>a[1],a[3]>a[2], dp[3]=max{dp[2],dp[1]}+1= 2

…………………………………………………

这样问题就就转化为在dp[1],dp[2],…,dp[n-1]的情况下如何求取dp[n]

若a[n]>a[i],a[n]>a[j],a[n]>a[k]….,(i,j,k…属于1至n-1)

dp[n]=max{dp[i],dp[j],dp[k],,,,,,}+1

若不满足

dp[n]=1

// DoubleLIS.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "stdio.h"
#define N 10
int dp[N];//表示从A[1]到A[i]中以A[i]结尾的最长子序列长度
int a[N] = {0,2,1,5,3,6,4,8,9,7};

int LIS(int n)  //从左往右最长序列的长度
{
	int ans = 1;
	for (int i = 2; i < N; i++)
	{
		int tmp = i;
		int max = 0;
		for (int j = 1; j < i; j++)
		{
			//从左向右搜索dp数组,若满足上升序列的条件
			//1.若a[i] > a[j]
			//找到dp数组中最大的值,即A[i]之前最大的值
			//2.若a[i]不满足a[i] > a[j]
			//则dp[i] = 1
			if (a[i] > a[j] && dp[j] > max)
			{
				tmp = j;
				max = dp[j];
			}
		}

		//最大值+1就是dp[i]
		dp[i] = dp[tmp] + 1;

		if (dp[i] > ans)
			ans = dp[i];
	}

	return ans;

}
int main(int argc, char* argv[])
{
	dp[1] = 1;
	printf("%d\n", LIS(N-1));  //从左往右最长序列的长度
	return 0;
}

尝试解释LIS(最长递增子序列)的一种动态规划算法

时间: 2024-10-10 15:08:24

尝试解释LIS(最长递增子序列)的一种动态规划算法的相关文章

算法设计 - LCS 最长公共子序列&amp;&amp;最长公共子串 &amp;&amp;LIS 最长递增子序列

出处 http://segmentfault.com/blog/exploring/ 本章讲解:1. LCS(最长公共子序列)O(n^2)的时间复杂度,O(n^2)的空间复杂度:2. 与之类似但不同的最长公共子串方法.最长公共子串用动态规划可实现O(n^2)的时间复杂度,O(n^2)的空间复杂度:还可以进一步优化,用后缀数组的方法优化成线性时间O(nlogn):空间也可以用其他方法优化成线性.3.LIS(最长递增序列)DP方法可实现O(n^2)的时间复杂度,进一步优化最佳可达到O(nlogn)

LIS 最长递增子序列问题

一,    最长递增子序列问题的描述 设L=<a1,a2,…,an>是n个不同的实数的序列,L的递增子序列是这样一个子序列Lin=<aK1,ak2,…,akm>,其中k1<k2<…<km且aK1<ak2<…<akm.求最大的m值. 比如int* inp = {9,4,3,2,5,4,3,2}的最长递减子序列为{9,5,4,3,2}: 二,解决: 1.用一个临时数组tmp保存这样一种状态:tmp[i]表示以i为终点的递增序列的长度: 比如inp =

算法--字符串:最长递增子序列LIS

转自:labuladong公众号 很多读者反应,就算看了前文 动态规划详解,了解了动态规划的套路,也不会写状态转移方程,没有思路,怎么办?本文就借助「最长递增子序列」来讲一种设计动态规划的通用技巧:数学归纳思想.  最长递增子序列(Longest Increasing Subsequence,简写 LIS)是比较经典的一个问题,比较容易想到的是动态规划解法,时间复杂度 O(N^2),我们借这个问题来由浅入深讲解如何写动态规划. 比较难想到的是利用二分查找,时间复杂度是 O(NlogN),我们通过

POJ 2533 Longest Ordered Subsequence【最长递增子序列】【DP思想】

Longest Ordered Subsequence Time Limit : 4000/2000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Other) Total Submission(s) : 6   Accepted Submission(s) : 1 Problem Description A numeric sequence of ai is ordered ifa1 < a2 < ... < aN. Let t

最长递增子序列 LIS 时间复杂度O(nlogn)的Java实现

关于最长递增子序列时间复杂度O(n^2)的实现方法在博客http://blog.csdn.net/iniegang/article/details/47379873(最长递增子序列 Java实现)中已经做了实现,但是这种方法时间复杂度太高,查阅相关资料后我发现有人提出的算法可以将时间复杂度降低为O(nlogn),这种算法的核心思想就是替换(二分法替换),以下为我对这中算法的理解: 假设随机生成的一个具有10个元素的数组arrayIn[1-10]如[2, 3, 3, 4, 7, 3, 1, 6,

最长公共子序列(LCS)、最长递增子序列(LIS)、最长递增公共子序列(LICS)

最长公共子序列(LCS) [问题] 求两字符序列的最长公共字符子序列 问题描述:字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X的子序列,存在X的一个严格递增下标序列<i0,i1,…,ik-1>,使得对所有的j=0,1,…,k-1,有xij=yj.例如,X=“ABCBDAB”,Y=“BCDB”是X的一个子序列. 考虑最长公共子序列问题如何分解成

动态规划(DP),最长递增子序列(LIS)

题目链接:http://poj.org/problem?id=2533 解题报告: 状态转移方程: dp[i]表示以a[i]为结尾的LIS长度 状态转移方程: dp[0]=1; dp[i]=max(dp[k])+1,(k<i),(a[k]<a[i]) #include <stdio.h> #define MAX 1005 int a[MAX];///存数据 int dp[MAX];///dp[i]表示以a[i]为结尾的最长递增子序列(LIS)的长度 int main() { int

最长递增子序列(LIS)求解

问题描述 最长递增子序列也称 "最长上升子序列",简称LIS ( longest increasing subsequence).设L=<a1,a2,-,an>是n个不同的实数的序列,L的递增子序列是这样一个子序列Lis=<ak1,ak2,-,akm>,其中k1<k2<-<km且ak1<ak2<-<akm.求最大的m值. 如:求一个一维数组arr[i]中的最长递增子序列的长度,如在序列{ 7, 1, 6, 5, 3, 4, 8

LIS(最长递增子序列)和LCS(最长公共子序列)的总结

最长公共子序列(LCS):O(n^2) 两个for循环让两个字符串按位的匹配:i in range(1, len1) j in range(1, len2) s1[i - 1] == s2[j - 1], dp[i][j] = dp[i - 1][j -1] + 1; s1[i - 1] != s2[j - 1], dp[i][j] = max (dp[i - 1][j], dp[i][j - 1]); 初始化:dp[i][0] = dp[0][j] = 0; 伪代码: dp[maxn1][ma