本题采用类似耐心排序的算法,通过二分查找的方式,将题目的复杂度将为(NlogN)。通过二分查找的方式可以成功地获得最长递增子序列的大小,并保证所得子序列是严格字典序的。该题的难点在于如何获得子序列中的每个元素,我们采用一个index数组记录以序号为i为结尾的最长递增子序列的长度,一个MaxInd数字记录整个数列的最长递增子序列末尾元素在veci数组中的序号,并通过倒序便利将字典序最小的最长递增子序列加入到数组res中。

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

int main() {                           //耐心排序算法
    int vecSize;
    scanf("%d", &vecSize);
    vector<int> veci = vector<int>(vecSize);
    for(int i = 0; i < vecSize; ++i)
    {
        int vec;
        scanf("%d", &vec);
        veci[i] = vec;
    }
    vector<int> pile = vector<int>(vecSize);
    vector<int> index = vector<int>(vecSize);
    int piles = 0;
    int MaxInd = 0;
    for(int i = 0; i < vecSize; ++i)
    {
        int left = 0;
        int right = piles;
        int poker = veci[i];
        while(left < right)       //只能使用左开右闭区间否则出现错误
        {
            int mid = left + (right - left) / 2;
            if(pile[mid] > poker)
            right = mid;
            else if(pile[mid] < poker)
            left = mid + 1;
            else
            right = mid;
        }
        if(left == piles) ++piles;    
        pile[left] = poker;
        index[i] = left + 1;     //记录以i结尾时最长递增子序列的长度
        if(index[i] == piles)    //MaxInd记录最长递增子序列末尾元素的序号
        {
            MaxInd = i;
        }
    }
    vector<int> res = vector<int>(piles);
    int count = piles;
    for(int i = MaxInd; i >= 0; --i)
    {
        if(index[i] == count)
        {
            res[--count] = veci[i];
        }
    }
    for(int i = 0; i < piles; ++i)
    {
        printf("%d", res[i]);
        printf(" ");
    }
    return 0;
}