Algorithm 最长递增子序列(O(nlogn))

Algorithm 最长递增子序列(O(nlogn)),algorithm,lis,Algorithm,Lis,有一件事我不明白: 为什么X[M[i]]是一个非递减序列?算法背后的基本思想是保持给定长度的列表以尽可能小的元素结尾。构建这样的序列 在已知的最后一个元素序列中查找前一个元素(假设其长度为k) 尝试将当前元素附加到此序列,并为k+1长度构建新的更好的解决方案 因为在第一步中,您搜索较小的值,然后是X[i],所以新的解决方案(对于k+1)将使最后一个元素的顺序大于或短 我希望它能有所帮助。让我们先看看n^2算法: dp[0] = 1; for( int i = 1; i < len; i++

有一件事我不明白:


为什么X[M[i]]是一个非递减序列?

算法背后的基本思想是保持给定长度的列表以尽可能小的元素结尾。构建这样的序列

  • 在已知的最后一个元素序列中查找前一个元素(假设其长度为
    k
  • 尝试将当前元素附加到此序列,并为
    k+1
    长度构建新的更好的解决方案
  • 因为在第一步中,您搜索较小的值,然后是X[i],所以新的解决方案(对于
    k+1
    )将使最后一个元素的顺序大于或短


    我希望它能有所帮助。

    让我们先看看n^2算法:

    dp[0] = 1;
    for( int i = 1; i < len; i++ ) {
       dp[i] = 1;
       for( int j = 0; j < i; j++ ) {
          if( array[i] > array[j] ) {
             if( dp[i] < dp[j]+1 ) {
                dp[i] = dp[j]+1;
             }
          }
       }
    }
    
    dp[0]=1;
    对于(int i=1;i数组[j]){
    if(dp[i]
    现在改进发生在第二个循环中,基本上,您可以通过使用二进制搜索来提高速度。除了数组dp[],我们还有另一个数组c[],c非常特殊,c[i]表示:长度为i的最长递增序列的最后一个元素的最小值

    sz = 1;
    c[1] = array[0]; /*at this point, the minimum value of the last element of the size 1 increasing sequence must be array[0]*/
    dp[0] = 1;
    for( int i = 1; i < len; i++ ) {
       if( array[i] < c[1] ) {
          c[1] = array[i]; /*you have to update the minimum value right now*/
          dp[i] = 1;
       }
       else if( array[i] > c[sz] ) {
          c[sz+1] = array[i];
          dp[i] = sz+1;
          sz++;
       }
       else {
          int k = binary_search( c, sz, array[i] ); /*you want to find k so that c[k-1]<array[i]<c[k]*/
          c[k] = array[i];
          dp[i] = k;
       }
    }
    
    sz=1;
    c[1]=数组[0]/*此时,大小1递增序列的最后一个元素的最小值必须为数组[0]*/
    dp[0]=1;
    对于(int i=1;ic[sz]){
    c[sz+1]=数组[i];
    dp[i]=sz+1;
    sz++;
    }
    否则{
    int k=binary_search(c,sz,array[i]);/*您希望找到k,以便c[k-1]这是来自的O(n*lg(n))解决方案(注意:此实现假设列表中没有重复项):

    set-st;
    set::迭代器;
    圣克利尔();
    
    对于(i=0;i我们需要维护递增序列的列表

    通常,我们有一组不同长度的活动列表。我们将向这些列表中添加一个元素A[i]。我们将按长度的降序扫描列表(针对结束元素)。我们将验证所有列表的结束元素,以查找结束元素小于[i](下限值)的列表

    我们的战略由以下条件决定,
    1.如果[i]在所有活动列表的最终候选中最小,我们将开始长度为1的新活动列表。
    2.如果一个[i]在所有活动列表的最终候选中是最大的,我们将克隆最大的活动列表,并将其扩展一个[i]。
    3.如果[i]介于两者之间,我们将找到一个具有比[i]小的最大结束元素的列表。克隆此列表并将其扩展[i]。我们将丢弃与此修改列表长度相同的所有其他列表。

    请注意,在我们构建活动列表的过程中,始终保持以下条件

    较小列表的结束元素小于较大列表的结束元素。

    举个例子就很清楚了,让我们从维基上举个例子:
    {0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15}

    A[0]=0.情况1.没有活动列表,请创建一个。
    0.
    --------------------------------------------------------------
    A[1]=8.案例2.克隆和扩展。
    0.
    0,8.
    --------------------------------------------------------------
    A[2]=4.案例3.克隆、扩展和放弃。
    0.
    0,4.
    0、8.丢弃
    --------------------------------------------------------------
    A[3]=12.案例2.克隆和扩展。
    0.
    0,4.
    0,4,12.
    --------------------------------------------------------------
    A[4]=2.案例3.克隆、扩展和放弃。
    0.
    0,2.
    0、4.丢弃。
    0,4,12.
    --------------------------------------------------------------
    A[5]=10.案例3.克隆、扩展和放弃。
    0.
    0,2.
    0,2,10.
    0、4、12.丢弃。
    --------------------------------------------------------------
    A[6]=6.案例3.克隆、扩展和放弃。
    0.
    0,2.
    0,2,6.
    0、2、10.丢弃。
    --------------------------------------------------------------
    A[7]=14.案例2.克隆和扩展。
    0.
    0,2.
    0,2,6.
    0,2,6,14.
    --------------------------------------------------------------
    A[8]=1.案例3.克隆、扩展和放弃。
    0.
    0,1.
    0、2.丢弃。
    0,2,6.
    0,2,6,14.
    --------------------------------------------------------------
    A[9]=9.案例3.克隆、扩展和放弃。
    0.
    0,1.
    0,2,6.
    0,2,6,9.
    0、2、6、14.丢弃。
    --------------------------------------------------------------
    A[10]=5.案例3.克隆、扩展和放弃。
    0.
    0,1.
    0,1,5.
    0、2、6.丢弃。
    0,2,6,9.
    --------------------------------------------------------------
    A[11]=13.案例2.克隆和扩展。
    0.
    0,1.
    0,1,5.
    0,2,6,9.
    0,2,6,9,13.
    --------------------------------------------------------------
    A[12]=3.案例3.克隆、扩展和放弃。
    0.
    0,1.
    0,1,3.
    0、1、5.丢弃。
    0,2,6,9.
    0,2,6,9,13.
    --------------------------------------------------------------
    A[13]=11.案例3.克隆、扩展和放弃。
    0.
    0,1.
    0,1,3.
    0,2,6,9.
    0,2,6,9,11.
    0、2、6、9、13.丢弃。
    --------------------------------------------------------------------
    set<int> my_set;
    set<int>::iterator it;
    vector <int> out;
    out.clear();
    my_set.clear();
    for(int i = 1; i <= n; i++) {
        my_set.insert(a[i]);
        it = my_set.find(a[i]);
        it++;
        if(it != my_set.end()) 
            st.erase(it);
        else
            out.push_back(*it);
    }
    cout<< out.size();
    
    //! card piles contain pile of cards, nth pile contains n cards.
    int top_card_list[n+1];
    for(int i = 0; i <= n; i++) {
        top_card_list[i] = -1;
    }
    
                 3
      *   7      2                   
    -------------------------------------------------------------
      Pile of cards above (top card is larger than lower cards)
     (note that pile of card represents longest increasing subsequence too !)
    
    for(int i = 1; i < n; i++) { // outer loop
        for(int j = 0; j < i; j++) { // inner loop
            if(arr[i] > arr[j]) {
                if(memo_len[i] < (memo_len[j]+1)) {
                    // relaxation
                    memo_len[i] = memo_len[j]+1;
                    result = std::max(result,memo_len[i]);
                    pred[i] = j;
                }
            }
        }
     }
    
    for(int i = 1; i < n; i++) {
        pile_height[i] = 1;
        const int j = pile_search(top_card_list, arr, pile_len, arr[i]);
        if(arr[i] > arr[j]) {
            if(pile_height[i] < (pile_height[j]+1)) {
                // relaxation
                pile_height[i] = pile_height[j]+1;
                result = std::max(result,pile_height[i]);
                pile_len = std::max(pile_len,pile_height[i]);
            }
        }
        if(-1 == top_card_list[pile_height[i]] || arr[top_card_list[pile_height[i]]] > arr[i]) {
            top_card_list[pile_height[i]] = i; // top card on the pile is now i
        }
    }
    
    inline static int pile_search(const int*top_card_list, const vector<int>& arr, int pile_len, int strict_upper_limit) {
        int start = 1,bound=pile_len;
        while(start < bound) {
            if(arr[top_card_list[bound]] < strict_upper_limit) {
                return top_card_list[bound];
            }
            int mid = (start+bound)/2 + ((start+bound)&1);
            if(arr[top_card_list[mid]] >= strict_upper_limit) {
                // go lower
                bound = mid-1;
            } else {
                start = mid;
            }
        }
        return top_card_list[bound];
    }
    
    int n;
    cin>>n;//LENGTH OF ARRAY
    vector<int>v(n);
    for(int i=0;i<n;i++){
        cin>>v[i];
    }
    vector<int>d(n+1,INT_MAX);//AUXILLARY ARRAY
    for(int i=0;i<=n;i++){
        *lower_bound(d.begin(),d.end(),v[i])=v[i];
    }
    for(int i=0;i<n;i++){
        if(d[i]==INT_MAX){
            cout<<i;//LENGTH OF LIS
            exit(0);
        }
    }