lintcode--010 (Longest ascending subsequence)

Source: Internet
Author: User
Tags lintcode

Given an integer sequence, the longest ascending subsequence (LIS) is found, returning the length of the LIS. LIS (longestincreasingsubsequence)

Description

Definition of the longest ascending sub-sequence:

The longest ascending subsequence problem is finding a sequence that is as long as possible from low to high in a given sequence of unordered order, which is not necessarily sequential or unique.
The longest ascending subsequence problem, that is Longest increasing subsequence , the abbreviation LIS . Is the problem of finding the longest ascending sub-sequence in a sequence, which is a fairly classical problem in dynamic programming. As we can see here, this ascent is essentially a < process of defining, so what we are solving is actually a kind of problem, that is, in a given sequence, the longest length of a sub-sequence conforming to a certain property is solved.

Sample Example

Give [5,4,1,2,3] , LIS Yes [1,2,3] , return3
Give [4,2,4,5,3,7] , LIS Yes [2,4,5,7] , return4

challenges

Requires a time complexity of O (n^2) or O (NLOGN)

labelDichotomy Lintcode All rights reserved Dynamic planning Problem Solving, analysis:If the longest ascending subsequence can be solved, then return its length. Idea 1: You can sort all the numbers first, first find the smallest number and where it is, and then look backwards from there, if the subsequent number is greater than it, then num+1 until the end; then on the second small number, in the operation above again,   If NUM is less than the first time, then keep the first time unchanged, if greater than the second number.          .........  Until the end. That's a lot of complexity, ==!. Idea 2: Dynamic solver. (Key to Master) dp[i]Represents the length of the LIS in a subsequence ending with I. Then I used dp[j](0<=j<i)To represent the length of the LIS before I. And then we can see that only when a[i]>a[j], we need to decide whether to add a[i] to dp[j]. In order to ensure that each time we join are to get an optimal lis, there are two points to note: First, every time, a[i] should be added to the largest dp[j], to ensure that the local nature of the best, that is, we need to find max(dp[j](0<=j<i))Second, after each accession, we should update the value of Dp[j], obviously, dp[i]=dp[j]+1
If we write a recursive formula, we can get dp[i]=max(dp[j](0<=j<i))+(a[i]>a[j]?1:0)
so we are able to get O (n^2) dynamic programming method.
classSolution { Public:    /** * @param nums:the integer array * @return: The length of LIS (longest increasing subsequence)*/    intLongestincreasingsubsequence (vector<int>nums) {        //Write your code here        intn=nums.size (); intDp[n]; Memset (DP,0,sizeof(DP)); intMax;  for(intI=0; i<n;i++) {Max=0;  for(intj=0; j<i;j++){                if(nums[i]>Nums[j]) {Max=Max (max,dp[j]); }} Dp[i]=max+1; } Max=0;  for(intI=0; i<n;i++){            if(dp[i]>Max) {Max=Dp[i]; }        }        returnMax; }};

The above method, we spend a lot of time looking for the biggest dp[j]. If there is a way to make this dp[j] into an ascending sequence, we can use two points to optimize it, thus reducing the complexity O(nlogn) .

Method 3: Sort the +LCS algorithm (also good, apply) Method 4: Dynamic programming + dichotomy (highest efficiency) transferred from:https://www.felix021.com/blog/read.php?1587
Suppose there is a sequence d[1..9] = 2 1 5 3 6 4 8 9 7, it can be seen that the LIS length is 5.
Try to find it step by step below.
We define a sequence B and then let i = 1 to 9 examine the sequence one at a.
In addition, we use a variable len to record the maximum number of times now.

First, put d[1] in order B, make b[1] = 2, that is, when there are only 11 digits 2, the smallest end of the LIS with a length of 1 is 2. Then Len=1

Then, put d[2] in an orderly place in B, so that b[1] = 1, that is, the minimum length of the LIS is 1,d[1]=2 is useless, it is easy to understand it. Then Len=1

Next, d[3] = 5,d[3]>b[1], so make b[1+1]=b[2]=d[3]=5, that is, the minimum end of the LIS with a length of 2 is 5, it is easy to understand. This time b[1..2] = 1, 5,len=2

Again, d[4] = 3, it just add to 1, 5, placed in the position of 1 is obviously inappropriate, because 1 is less than 3, the minimum length of the LIS is 1, so it is easy to infer that the length of the LIS min 1 is 2, so you can eliminate 3, this time b[1..2] = 5, 3,len = 1

Continue, d[5] = 6, it is behind 3, because b[2] = 3, and 6 is behind 3, so it is easy to infer b[3] = 6, then b[1..3] = 1, 3, 6, or is it easy to understand? Len = 3, OH.

6th, D[6] = 4, you see it between 3 and 6, so we can replace 6, get b[3] = 4. B[1..3] = 1, 3, 4, Len continues to be equal to 3

7th one, d[7] = 8, it's big, bigger than 4, uh. So b[4] = 8. Len becomes 4.

8th, D[8] = 9, get b[5] = 9, uh. Len continues to grow, to 5.

The last one, d[9] = 7, which is between b[3] = 4 and b[4] = 8, so we know that the latest b[4] =7,b[1..5] = 1, 3, 4, 7, 9,len = 5.

So we know the length of the LIS is 5.

!!!!! Attention. This 1,3,4,7,9 is not the LIS, it just stores the corresponding length to the minimum end of the LIS. With this at the end, we can insert data one at a-one place. Although the last d[9] = 7 update is not meaningful for this set of data, but if there are two numbers 8 and 9, then you can update 8 to d[5], 9 update to d[6], the length of the LIS is 6.

then you should find one thing: inserting data in B is ordered and is replaced without moving--that is, we can use a binary search to optimize the insertion time of each number to O (logn) ~~~~~ The time complexity of the algorithm is reduced to O (NLOGN)! Code:
Arr[s in non-descending sequence: E] (closed interval) find the first position greater than or equal to key, if both are less than key, return e+1int upper_bound (int arr[], int s, int e, int key) {    int mid;    if (Arr[e] <= key)        return e + 1;    while (S < e)    {        mid = s + (e-s)/2;        if (Arr[mid] <= key)            s = mid + 1;        else            e = mid;    }    return s;} int LIS (int d[], int n) {    int i = 0, Len = 1, *end = (int *) alloca (sizeof (int) * (n + 1));    END[1] = d[0]; Initialization: 1 Lis end is d[0] for    (i = 1; i < n; i++)    {        int pos = Upper_bound (end, 1, Len, d[i]);//Find insertion position        End[pos] = D[i];        if (Len < POS)//update LIS length as needed            len = pos;    }    return Len;}

Another implementation code:
classSolution { Public:    /** * @param nums:the integer array * @return: The length of LIS (longest increasing subsequence)*/    intLongestincreasingsubsequence (vector<int>nums) {        //Write your code here        intn=nums.size (); intDp[n]; if(n==0){            return 0; } memset (DP,0,sizeof(int)*N); intlen=1; dp[0]=nums[0];  for(intI=1; i<n;i++){            intPos=lower_bound (Dp,dp+len,nums[i])-DP; Dp[pos]=Nums[i]; Len=max (len,pos+1); }        returnLen; }};

In the second approach, we spend a lot of time looking for the biggest dp[j]. If there is a way to make this dp[j] into an ascending sequence, we can use two points to optimize it, thus reducing the complexity O(nlogn) .
Fortunately, this approach does exist. We can use Dp[i] to save the largest number in the first I number, it is easy to understand that this dp[i] is already monotonous. The next process is actually some greedy ideas, for each a[i], we are in the DP array looking for the first number of the largest, it may be set to POS, and then use A[i] to update Dp[pos]. So we can see that Len should be max(len, pos+1) .

Here we use the Lower_bound function, which returns a pointer to the first value that is less than or equal to Val, and returns the end pointer if it does not exist.

lintcode--010 (Longest ascending subsequence)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.