最长单调递增子序列
2014-05-25 21:40
183 查看
问题描述:
求一个正整数序列的最长单调自增子序列,子序列不要求是连续的。例如
Input:5
5 2 4 3 1
Output:2
(1) 算法复杂度是O(N*N)
f[i]是以a[i]为最大值的子序列,那么f[]的最大值就是要的结果。
转载请尊重原创、保留相关链接本文来自多宝平台:http://www.mbodb.com
点击(此处)折叠或打开
int f[],a[];
f[0] = 1;
for(i = 1 ; i < n ; i++ )
{
f[i] = 1;
for(j = 0 ; j < i ; j++)
{
If(a[j] < a[i] && f[j]+1 > f[i])//等号有没有要视题目而定
{
f[i] = f[j] +1;
}
}
}
很显然实践复杂度是O(N*N),那么有没有更快的算法呢?按照正常的思路更快的复杂度应该就是O(N*logN),那么就要涉及到二分了。
(2)算法复杂度是O(N*logN)
对于序列Sn,考虑其长度为i的单调子列(1<=i<=m),多宝这样的子列可能有多个。我们选取这些子列的结尾元素(子列的最后一个元素)的最小值。用Li表示。那么:
L1<=L2<=…<=Lm
因为:如果Li>Lj(i<j),那么去掉以Lj结尾的递增子序列的最后j-i个元素,得到一个长度为i的子序列,该序列的结尾元素ak<=Lj<Li,这与Li标识了长度为i的递增子序列的最小结尾元素相矛盾,于是证明了上述结论。(注:之前要使L保存这些序列的最小值就是为了使此公式成立,即L有序。只有L有序我们才能方便的利用二分查找法创建L)。
现在,我们来寻找Sn对应的L序列,如果我们找到的最大的Li是Lm,那么m就是最大单调子列的长度。下面的方法可以用来创建和维护L。
从左至右扫描Sn,对于每一个ai,它可能
(1) ai<L1,那么L1=ai
(2) ai>=Lm,那么Lm+1=ai,m=m+1 (其中m是当前见到的最大的L下标)
(3) ai<Lm,则找到s,使得Ls<=ai<Ls+1,那么Ls+1=ai
扫描完成后,我们也就得到了最长递增子序列的长度。从上述方法可知,对于每一个元素,我们需要对L进行查找操作,由于L有序,所以使用二分查找这个操作为logn,于是总的复杂度为O(nlogn)。优于开始O(n2)的算法。这里给出我的一个实现:(算法并没有返回具体的序列,只是返回长度)
点击(此处)折叠或打开
int find(int *a,int len,int n)//二分find
{
int left=0,right=len,mid=(left+right)/2;
while(left<=right)
{
if(n>a[mid]) left=mid+1;
else if(n<a[mid]) right=mid-1;
else return mid;
mid=(left+right)/2;
}
return left;//注:这里查找不到时要返回left,因为结束时left指向较大值。
}
L[0]=-1;//要懂得用这种天然的最小值
L[1]=a[0];//初始化
for(i=1;i<n;i++)//复杂度是N的
{
j=find(L,n+1,a[i]);//找到第三步中的s+1
L[j]=a[i];
}
求一个正整数序列的最长单调自增子序列,子序列不要求是连续的。例如
Input:5
5 2 4 3 1
Output:2
(1) 算法复杂度是O(N*N)
f[i]是以a[i]为最大值的子序列,那么f[]的最大值就是要的结果。
转载请尊重原创、保留相关链接本文来自多宝平台:http://www.mbodb.com
点击(此处)折叠或打开
int f[],a[];
f[0] = 1;
for(i = 1 ; i < n ; i++ )
{
f[i] = 1;
for(j = 0 ; j < i ; j++)
{
If(a[j] < a[i] && f[j]+1 > f[i])//等号有没有要视题目而定
{
f[i] = f[j] +1;
}
}
}
很显然实践复杂度是O(N*N),那么有没有更快的算法呢?按照正常的思路更快的复杂度应该就是O(N*logN),那么就要涉及到二分了。
(2)算法复杂度是O(N*logN)
对于序列Sn,考虑其长度为i的单调子列(1<=i<=m),多宝这样的子列可能有多个。我们选取这些子列的结尾元素(子列的最后一个元素)的最小值。用Li表示。那么:
L1<=L2<=…<=Lm
因为:如果Li>Lj(i<j),那么去掉以Lj结尾的递增子序列的最后j-i个元素,得到一个长度为i的子序列,该序列的结尾元素ak<=Lj<Li,这与Li标识了长度为i的递增子序列的最小结尾元素相矛盾,于是证明了上述结论。(注:之前要使L保存这些序列的最小值就是为了使此公式成立,即L有序。只有L有序我们才能方便的利用二分查找法创建L)。
现在,我们来寻找Sn对应的L序列,如果我们找到的最大的Li是Lm,那么m就是最大单调子列的长度。下面的方法可以用来创建和维护L。
从左至右扫描Sn,对于每一个ai,它可能
(1) ai<L1,那么L1=ai
(2) ai>=Lm,那么Lm+1=ai,m=m+1 (其中m是当前见到的最大的L下标)
(3) ai<Lm,则找到s,使得Ls<=ai<Ls+1,那么Ls+1=ai
扫描完成后,我们也就得到了最长递增子序列的长度。从上述方法可知,对于每一个元素,我们需要对L进行查找操作,由于L有序,所以使用二分查找这个操作为logn,于是总的复杂度为O(nlogn)。优于开始O(n2)的算法。这里给出我的一个实现:(算法并没有返回具体的序列,只是返回长度)
点击(此处)折叠或打开
int find(int *a,int len,int n)//二分find
{
int left=0,right=len,mid=(left+right)/2;
while(left<=right)
{
if(n>a[mid]) left=mid+1;
else if(n<a[mid]) right=mid-1;
else return mid;
mid=(left+right)/2;
}
return left;//注:这里查找不到时要返回left,因为结束时left指向较大值。
}
L[0]=-1;//要懂得用这种天然的最小值
L[1]=a[0];//初始化
for(i=1;i<n;i++)//复杂度是N的
{
j=find(L,n+1,a[i]);//找到第三步中的s+1
L[j]=a[i];
}
相关文章推荐
- 一路二路最长单调递增子序列 hdu3998 + ACdream 1216
- poj1631Bridging signals(最长单调递增子序列 nlgn)
- 最长单调递增子序列
- 最长单调递增子序列问题
- 分享:最长单调递增子序列
- 最长单调递增子序列的三种解法
- 最长单调递增子序列。
- HD1160FatMouse's Speed(最长单调递增子序列)
- 算法_动态规划_最长单调递增子序列
- 最长单调递增子序列
- 最长单调递增子序列, 子串和
- 求非连续最长单调递增子序列
- 飞翔(最长单调递增子序列)
- 动态规划题目一:最长单调递增子序列
- 算法导论15.4-6:最长单调递增子序列
- 最长单调递增子序列问题
- (p226)最长单调递增子序列
- 动态规划题目一:最长单调递增子序列
- 最长单调递增子序列
- 最长单调递增子序列