最长上升子序列(Longest Increasing Subsequence,LIS),在计算机科学上是指一个序列中最长的单调递增的子序列。
O(n^2)复杂度:
最长上升子序列(最长不下降子序列):
两者严格的区别是前者是严格递增的,后者允许有相同的值存在。
for(int i = 1;i <= n;i ++)
{
dp[i] = 1;
for(int j = 1;j < i;j ++)
{
if(a[i] > a[j]) //此处如果改为 a[i] >= a[j] 那么求的则是最长不下降子序列
dp[i] = max(dp[i], dp[j] + 1);
}
//ans = max(ans,dp[i]);
}
//cout << ans << endl;
最长下降子序列(最长不上升子序列):
for(int i = 1;i <= n;i ++)
{
dp[i] = 1;
for(int j = 1;j < i;j ++)
{
if(a[i] < a[j]) //此处如果改为 a[i] <= a[j] 那么求的则是最长不下降子序列
dp[i] = max(dp[i], dp[j] + 1);
}
ans = max(ans,dp[i]);
}
cout << ans << endl;
O(nlogn)复杂度:
运用 二分+贪心 实现
我们需要新建一个数组b 初始化都为inf 即很大的数,二分去找大于等于它的数 ,然后替换它 ,最后数出来有多少个数字不是
inf,就是长度,同时还能记录路径,一举两得
最长不下降子序列:
int b[n];
memset(b,inf,sizeof(b));
for(int i = 1;i <= n;i ++)
{
int pos = lower_bound(b + 1,b + n + 1, a[i]) - b;
b[pos] = a[i];
}
int ans = 0;
for(int i = 1;i <= n;i ++)
if(b[i] != inf) ans ++;
cout << ans << endl;
最长上升子序列只需要把里面的lower_bound 改为 upper_bound即可
最长下降子序列:
原理与上述类似 将a数组翻转,再求
注意:最长下降子序列是在原数组a翻转过后用lower_bound,而最长不上升子序列则是用upper_bound 这点需要特别留心
int b[n];
memset(b,inf,sizeof(b));
reverse(a + 1,a + n +1);
for(int i = 1;i <= n;i ++)
{
int pos = lower_bound(b + 1,b + n + 1, a[i]) - b;
b[pos] = a[i];
}
int ans = 0;
for(int i = 1;i <= n;i ++)
if(b[i] != inf) ans ++;
cout << ans << endl;