Detailed explanation of the longest ascending subsequence O(nlogn) algorithm

longest ascending subsequence

Time Limit: 10 Sec Memory Limit: 128 MB

Topic description

Given a sequence, initially empty. Now we insert numbers from 1 to N into the sequence, one number at a time at a specific position. We want to know what is the length of the longest ascending subsequence at this time?

enter

The first line contains an integer N, indicating that we want to insert 1 to N into the sequence, followed by N numbers, and the k-th number Xk, indicating that we will insert k at position Xk (0<=Xk<=k-1, 1<=k<=N)

output

1 line, what is the length of the longest ascending subsequence.

sample input

3

0 0 2

Sample output

2

hint

100% of the data n<=100000

O(nlogn) algorithm code :

  View Code

Code Analysis:

The first idea is to use dynamic programming. Obviously, the transfer equation of this problem is very, very simple. It is clear at a glance. First prepare an array b

b[i]=1;
, starting from a[1] to find the longest ascending subsequence of i .

Although this assignment statement is easy to understand, each element can also be regarded as a subsequence that matches the meaning of the question.

What about b[2] ?

As shown in the figure, it is obviously higher than a[1] , when the following statement is executed

for(j=1;j<i;j++)   if(a[i]>a[j])

j is less than i , that is , 2. At present, only a[1] is eligible , and a[1] has passed the judgment statement. It is indeed less than a[i] , and the next statement is executed:

b[i]=max(b[i],b[j]+1);

Obviously : b[2] is obviously 1. When it is compared with b[1]+1 , 1 is of course smaller than 2 , so b[2] is naturally 2 .

Let's take a look at the time complexity:

Obviously, the time complexity is O(n^2) .


So, is this method fast enough? It's ok, but still a little underwhelming.

The code is as follows O(n^2):

 1 #include<iostream>  
  2  using  namespace std;
  3  int i,j,n,a[ 100 ],b[ 100 ],max;    
  4  int main()  
  5 {
  6      cin>> n;
  7      for (i= 0 ;i<n;i++) cin>> a[i];  
  8      b[ 0 ]= 1 ; // initialization, the longest increasing subsequence ending with a[0] has length 1   
 9      for (i= 1 ;i <n;i++ )  
 10      {  
 11          b[i]= 1 ;//b[i]最小值为1
12         for(j=0;j<i;j++)  
13             if(a[i]>a[j]) b[i]=max(b[i],b[j]+1);
14     }  
15     for(max=i=0;i<n;i++) if(b[i]>max) max=b[i];  
16     cout<<max<<endl;
17 }
View Code

So, is there a faster way?

Of course, have you ever thought about why you need to record data?

We can simulate a stack

In the case of a large amount of data, this algorithm is very efficient

But how to optimize the program?

We can simulate it like this:

Each time a number is entered, if the number is greater than the number at the top of the stack, it is pushed onto the stack.

 

However, if this number is greater than the top of the stack, it does not prove that it cannot update the

For a certain element, at this time, you can use binary search.

     Some people may ask: This sequence is disordered. Yes, but the elements in the stack are searched , and all elements in the stack are strictly increasing, so using binary search can reduce the problem to O(nlogn) .

     Some are illogical, aren't they? The subscript of 15 is larger than that of 17 , 18 and 20. Why can it be inserted? But if you think about it, it doesn't seem to affect the normal answer, but if you want to output the longest ascending subsequence, you have to change the algorithm.

The entire binary search code is as follows:

else

{

    int l=1,h=s,m;

    while(l<=h)

    {

         m=(l+h)/2;

         if(t>a[m]) l=m+1;

         else h=m-1;

    }

    a[l]=t;

}

As a result, the search algorithm can be reduced to logn , so the overall is O(nlogn) .

The specific operations are as follows :

Each time the top element of the stack is taken and the read element is compared , if it is greater than, it will be pushed into the stack; if it is less than, the first number in the stack that is greater than it will be searched binary and replaced. The longest sequence length is the size of the last simulation.

This is also well understood, for i and j , if i < j and a[i] < a[j], replace a[j] with a[ i ] , the length does not change but the ' potential ' of a increases .

Code (same as above):

#include <iostream>
using namespace std; 
int i,j,n,s,t,a[100001];
int main()
{
    cin>>n;
    a[0]=-1000000;
    for(i=0;i<n;i++)
    {
        cin>>t;
        if(t>a[s]) a[++s]=t;
        else
        {
            int l=1,h=s,m;
            while(l<=h)
            {
                m=(l+h)/2;
                if(t>a[m]) l=m+1;
                else h=m-1;
            }
            a[l]=t;
        }
    }
    cout<<s<<endl;
}

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325891678&siteId=291194637