最长上升子序列的长度

描述
在一条单车道的公路上有N辆汽车行驶,从前向后第i辆车的最高速度是Vi。

所有车辆都会尽量保持最高速度行驶。不过由于只有单车道,所以当后方快车追上前方慢车后,无法超车,只能降速跟在慢车后面。

于是经过足够长时间(足够后方快车追上前方慢车)的行驶后,某些车辆会聚成一队以相同的速度向前行驶。我们把这些聚成一队的车辆称为一个”车队”。不同车队之间的距离会越来越大。

例如假设有5辆车,速度依次是[3, 5, 4, 1, 2],则经过足够长时间行驶后,第1、2、3辆会聚成一个车队,第4、5辆会聚成另一个车队。

现在假设你可以”拿掉”其中一些车辆,但不能改变剩余的车辆的前后次序和最高速度。请计算最少”拿掉”多少辆车,可以使得剩余的车辆数目恰好等于剩余车辆经过足够长时间行驶后形成的车队数量。(换句话说每辆车单独一个车队)

在上例中”拿掉”第一辆和第四辆之后,[5, 4, 2]会最终形成3个车队,满足条件。

输入
第一行包含一个整数N。

第二行包含N个整数V1, V2, … VN。

对于30%的数据,1 ≤ N ≤ 1000

对于100%的数据,1 ≤ N ≤ 100000, 1 ≤ Vi ≤ 100000, Vi保证两两不同。

输出
一个整数表示答案。

样例输入
5
3 5 4 1 2
样例输出
2

可用二分搜索法,开辟一数组存储最长上升子序列的长度,时间复杂度O(nlogn)。若求最长上升子序列,该方法不可用。

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>

using namespace std;

int main()
{
    int N; cin >> N;

    vector<int> v(N);

    for(int i=0; i<N; i++) cin >> v[i];

   vector<int> dp;

    for(int i=N-1; i>=0; --i)
    {
        if(dp.size()==0 || dp.back()<v[i])
            dp.push_back(v[i]);
        else{
            int low = 0, high = dp.size()-1;
            while(low <= high)
            {
                int mid = (low +high)/2;
                if(dp[mid]>v[i])
                    low = mid +1;
                else high = mid-1;
            }
            dp[low] = v[i];
        }
    }

    cout << N-dp.size() << endl;


    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_24153697/article/details/79057943