POJ3903 最长递增子序列

本文介绍了一种从O(n^2)优化到O(nlogn)的最长递增子序列算法,并提供了详细的实现思路及C++代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最长递增子序列,传统方法用dp思想,状态转移方程如下:

   dp[i] = Max{dp[j] | j < i && A[j] < A[i] } + 1;

传统写法是求dp[i]时枚举所有小于i的j,然后找一个最大的,最后加1得到dp[i],此方法复杂度是O(n^2)


有一种优化到O(n logn)的方法是这样的:

用maxV辅助数组,

maxV[i] 代表长度为i的递增子序列的最大元素的最小值。

我们会发现该数组是有序的,证明如下:

证明:反证法,假设当i<j<=k,有MaxV[i]>=MaxV[j],那么存在一个长度为i的递增序列a1a2...ai,且ai是计算到阶段k时所有长度为i的递增序列中最大元素的最小值,以及长度为j的序列b1b2...bj且ai>=bj,由于i<j长度j的序列b1b2...bj包含一个子序列b1b2...bi,且bi<bj<=ai,即长度为i的递增子序列最大元素的最小值不是ai,矛盾。

所以可以用二分查找来找到最长的可以将A[i]接到后面的子序列

代码如下(poj3903)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
using namespace std;


int LongestIncreasingSequence(const vector<long long>& array){
      int n = array.size();
      vector<int> maxV(n+1,0);
      maxV[1] = array[0];
      int ret = 1;
      for(int i = 1; i < n; ++i){
          int maxv = 1;
          int left = 1, right = ret;
          while(left <= right){
              int mid = left + (right - left) / 2;
              if(maxV[mid] < array[i])
                    left = mid + 1;
              else 
                    right = mid - 1;
          }
          
          maxV[right+1] = array[i]; 
          ret = std::max(right+1,ret);
      }
      return ret;
}
int main()
{
       int n;
       vector<long long> vec;
       while(scanf("%d",&n)!=EOF){
             vec.clear();
             vec.resize(n,0);
             for(int i = 0; i < n; ++i){
                   long long tmp;
                   scanf("%lld",&tmp);
                   vec[i] = tmp;
             }
             printf("%d\n",LongestIncreasingSequence(vec));
      }
      return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值