最长上升子序列的两种解法

最长上升子序列的两种解法问题描述一个数的序列bi,当b1你的任务,就是对于给定的序列,求出最长上升子序列的长度。动态规划法如何把这个问题分解成子问题呢?经过分析,发现“求以ak(k=1,2,3…N)为终点的最长上升子序列的长度”是个好的子问题――这里把一个上升子序列中最右边的那个数,称为该子序列的“终点”。虽然这个子问题和原问题形式上并不完全一样,但是只要这N个子问题都解决了,那么这N

大家好,又见面了,我是你们的朋友全栈君。

问题描述

一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < … < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8).

你的任务,就是对于给定的序列,求出最长上升子序列的长度。

动态规划法

如何把这个问题分解成子问题呢?经过分析,发现 “求以ak(k=1, 2, 3…N)为终点的最长上升子序列的长度”是个好的子问题――这里把一个上升子序列中最右边的那个数,称为该子序列的“终点”。虽然这个子问题和原问题形式上并不完全一样,但是只要这N个子问题都解决了,那么这N个子问题的解中,最大的那个就是整个问题的解。
由上所述的子问题只和一个变量相关,就是数字的位置。因此序列中数的位置k 就是“状态”,而状态 k 对应的“值”,就是以ak做为“终点”的最长上升子序列的长度。这个问题的状态一共有N个。状态定义出来后,转移方程就不难想了。假定MaxLen (k)表示以ak做为“终点”的最长上升子序列的长度,那么:
MaxLen (1) = 1
MaxLen (k) = Max { MaxLen (i):1<i < k 且 ai < ak且 k≠1 } + 1
这个状态转移方程的意思就是,MaxLen(k)的值,就是在ak左边,“终点”数值小于ak,且长度最大的那个上升子序列的长度再加1。因为ak左边任何“终点”小于ak的子序列,加上ak后就能形成一个更长的上升子序列。
实际实现的时候,可以不必编写递归函数,因为从 MaxLen(1)就能推算出MaxLen(2),有了MaxLen(1)和MaxLen(2)就能推算出MaxLen(3)……

#include <stdio.h>
#define  MAX 1000
int seq[MAX+10];
int seqlen[MAX+10];
int main()
{
	int i,j,k,N,max,maxlen=1;
	for(i=1;i<=9;i++)
		seqlen[i]=1;               //seqlen数组存以第i个数为终点的最长上升序列
	scanf("%d",&N);
	for(i=1;i<=N;i++)
		scanf("%d",&seq[i]);       //seq数组保存序列数组
	for (i=2;i<=N;i++)
	{
		max=0;
		for (j=1;j<=i-1;j++)
		{
			if(seq[j]<seq[i]&&seqlen[j]>max)  //在前i-1个序列中,寻找以终点小于seq[i]的最长的子序列,即最优子状态
				max=seqlen[j];
		}
		seqlen[i]=max+1;
		if(seqlen[i]>maxlen)           //seqlen中保存的是第i个数为终点的最长上升序列,找出这个数组中最大的值即为最优序列长度
			maxlen=seqlen[i];
	}
	printf("%d/n",maxlen);
	return 0;
}

最长上升子序列nlogn算法

假设存在一个序列d[1..9] = 2 1 5 3 6 4 8 9 7,可以看出来它的LIS长度为5。n
下面一步一步试着找出它。
我们定义一个序列B,然后令 i = 1 to 9 逐个考察这个序列。
此外,我们用一个变量Len来记录现在最长算到多少了

首先,把d[1]有序地放到B里,令B[1] = 2,就是说当只有1一个数字2的时候,长度为1的LIS的最小末尾是2。这时Len=1

然后,把d[2]有序地放到B里,令B[1] = 1,就是说长度为1的LIS的最小末尾是1,d[1]=2已经没用了,很容易理解吧。这时Len=1

接着,d[3] = 5,d[3]>B[1],所以令B[1+1]=B[2]=d[3]=5,就是说长度为2的LIS的最小末尾是5,很容易理解吧。这时候B[1..2] = 1, 5,Len=2

再来,d[4] = 3,它正好加在1,5之间,放在1的位置显然不合适,因为1小于3,长度为1的LIS最小末尾应该是1,这样很容易推知,长度为2的LIS最小末尾是3,于是可以把5淘汰掉,这时候B[1..2] = 1, 3,Len = 2

继续,d[5] = 6,它在3后面,因为B[2] = 3, 而6在3后面,于是很容易可以推知B[3] = 6, 这时B[1..3] = 1, 3, 6,还是很容易理解吧? Len = 3 了噢。

第6个, d[6] = 4,你看它在3和6之间,于是我们就可以把6替换掉,得到B[3] = 4。B[1..3] = 1, 3, 4, Len继续等于3

第7个, d[7] = 8,它很大,比4大,嗯。于是B[4] = 8。Len变成4了

第8个, d[8] = 9,得到B[5] = 9,嗯。Len继续增大,到5了。

最后一个, d[9] = 7,它在B[3] = 4和B[4] = 8之间,所以我们知道,最新的B[4] =7,B[1..5] = 1, 3, 4, 7, 9,Len = 5。

于是我们知道了LIS的长度为5。

!!!!! 注意。这个1,3,4,7,9不是LIS,它只是存储的对应长度LIS的最小末尾。有了这个末尾,我们就可以一个一个地插入数据。虽然最后一个d[9] = 7更新进去对于这组数据没有什么意义,但是如果后面再出现两个数字 8 和 9,那么就可以把8更新到d[5], 9更新到d[6],得出LIS的长度为6。

然后应该发现一件事情了:在B中插入数据是有序的,而且是进行替换而不需要挪动——也就是说,我们可以使用二分查找,将每一个数字的插入时间优化到O(logN)~~~~~于是算法的时间复杂度就降低到了O(NlogN)~!

#include <iostream>
#include<cstdio>
#include<string.h>
using namespace std;
#define Maxn 50010

typedef long long ll;
ll arr[Maxn],ans[Maxn],len;



int main()
{
    ll p,i,j,k;
    //scanf("%d",&T);
    //while(T--)
    //{
        scanf("%lld",&p);
        for(i=1;i<=p;i++)
        {
            scanf("%lld",&arr[i]);

        }
        ans[1]=arr[1];
        len=1;
        for(i=2;i<=p;i++)
        {
            if(arr[i]>ans[len])
                ans[++len]=arr[i];
            else{
                ll pos =lower_bound(ans+1,ans+len,arr[i])-ans;
                ans[pos]=arr[i];
            }

        }
        printf("%lld\n",len);
   // }
    return 0;
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/132293.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 什么什么ant(初级会计的职称是什么)

    2019独角兽企业重金招聘Python工程师标准>>>…

    2022年4月16日
    37
  • mac版的goland激活码【中文破解版】「建议收藏」

    (mac版的goland激活码)JetBrains旗下有多款编译器工具(如:IntelliJ、WebStorm、PyCharm等)在各编程领域几乎都占据了垄断地位。建立在开源IntelliJ平台之上,过去15年以来,JetBrains一直在不断发展和完善这个平台。这个平台可以针对您的开发工作流进行微调并且能够提供…

    2022年3月30日
    536
  • maven配置阿里云仓库地址

    maven配置阿里云仓库地址<mirror><id>nexus-aliyun</id><mirrorOf>central</mirrorOf><name>Nexusaliyun</name><url>http://maven.aliyun.com/nexus/content/groups/public</url></mirror>

    2022年6月25日
    26
  • 奉劝各位学弟学妹们,该打造你的技术影响力了!

    奉劝各位学弟学妹们,该打造你的技术影响力了!CSDN的学弟学妹们,大家好呀,我是沉默王二。放在一年前,打死我也不相信,这四个平淡无奇的字组合在一起竟然充满了魔力!2019年的时候,我看过一本书,名叫《影响力》,应该有不少学弟学妹也看过。但说实在的,这本书我就看了几页,就看不下去了,不是这书不好,而是我觉得它不适合我,因为我那时候没什么影响力(谦虚点)。没有影响力的时候想着怎么扩大影响力,我就觉得有点扯淡。就像没有财的时候想着理财一样,有点白日做梦。与其白日做梦,不如脚踏实地,换一句浅显易懂的话,就是,与其想着理财,不如想想怎么攒钱。如果连原

    2022年5月22日
    33
  • List数组转换JSON格式

    List数组转换JSON格式最近在写java,然后leader需要几个接口,里面的东西就是json格式。然后需求明白后,想了想思路:先把需要的东西从库里拿出来放到一个数组里面,然后再将数组转换成json,大体思路确定后,开始敲代码。首先List一个数组,将要转换的东西先放到configs数组里面:List&lt;Class&gt;configs=newArrayList&lt;Class&gt;();…

    2022年6月21日
    31
  • JS替换回车换行符[通俗易懂]

    JS替换回车换行符[通俗易懂]replace(/\r/ig,'<br>’).replace(/\n/ig,'<br>’)转载于:https://www.cnblogs.com/zhang9418hn/p/3670037.html

    2022年5月23日
    33

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号