核心思想:
dp[i] = max{dp[j]+1} 0<=j<i and a[j]<a[i]
维护单调队列d,其中队列的值为a数组的值,队列d中的每一个元素分别对应一个以该元素结尾的一个子序列,注意队列并不能保存改子序列的所有值的信息。
if a[i]>d[len]
d[len++]=a[i]
else
d[j+1]=a[i] and d[j]是第一个比a[i]小的数,因为我们应该尽量使得子序列末尾的元素小,长度才有可能长
构建单调队列的时候有以下几种情况:
1.只有一个元素
d[0]=a[i]
2.有两个元素a[low],a[high]
if a[low]<a[i]
d[high]=a[i]
else if a[low]>a[i]
d[low]=a[i]
else
不用交换,这里存在a[i]与d[low]与d[high]相等的情况
题目:点击打开链接
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 10005
using namespace std;
int n,len=0;
char a[N],d[N];
void input()
{
len=0;
cin>>a;
n=strlen(a);
}
void search(char key)
{
int low,high,mid;
low=0,high=len-1;
while(low<high-1)
{
mid=(low+high)>>1;
if(key==d[mid])
{
return ;
}
else if(key>d[mid])
low=mid;
else
{
high=mid;
}
}
if(d[low]>key)
d[low]=key;
else if (d[low]<key)
d[high]=key;
}
void getLIS()
{
for(int i=0; i<n; i++)
{
if(len==0||a[i]>d[len-1])
d[len++]=a[i];
else
{
search(a[i]);
}
}
cout<<len<<endl;
}
int main()
{
int m;
cin>>m;
while(m--)
{
input();
getLIS();
}
return 0;
}
1.改进:计算最长不递减子序列。
那么不能使用单调队列来优化,因为单调队列中存在相等的元素,那么新元素加入队列时,两种情况如下:
1.如果新元素比单调队列最后的元素大的话,加入队列后面。
2.如果新元素比单调队列最后的元素小的话:
2.1 如果队列中存在与该元素相等的元素,则需要加入队列中与它相等的元素后面。但是队列后面的元素的位置则发生了变化,所以破坏了队列所代表的含义,即每个元素都对应一个以该元素结尾,长度为改元素位置的子序列。
2.2 如果队列中不存在与该元素相等的元素,那么直接找到第一个比该元素大的元素,替换它就好了。
所以,这里只能使用O(n^2)的算法来计算,即dp[i] = max{dp[j]+1} a[j] <= a[i] and 0<=j<=i