Rise longest sequence (LIS) Two methods

Problem Description: ai a sequence number, when a1 <a2 <... <aS time, we call this sequence is rising.

For a given sequence (a1, a2, ..., aN), we can get some increase in sequence (ai1, ai2, ..., aiK), where 1 <= i1 <i2 <... < iK <= N.

For example, for the sequence (1, 7, 3, 5, 9, 4, 8), which rises some sequences, such as (1, 7), (3, 4, 8) and the like. The longest sequence length is 4,

Such sequences (1, 3, 5, 8). Your job is for a given sequence, the length of the longest rise determined sequence.

Input data

The first input line is the sequence length N (1 <= N <= 1000). The second line gives the sequence of N integers, are integers ranging from 0 to 10000.

Output requirements

The length of the longest sub-sequence rise.

Input Sample 71735948

Sample Output 4

 

Dynamic Programming:

  State equation: maxLen [i] = 1; (initial state)

      maxLen[i]=max(maxLen[i],maxLen[j]+1)

Code:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<string.h>
#include<math.h>
using namespace std;
typedef long long LL;
const int maxn=1e5+7;
const int maxm=2e5+7;
const long long mod=1e9+7;
int N,maxLen[maxn],s[maxn];
int main()
{
    scanf("%d",&N);
    for(int i=1;i<=N;i++)
    {
        scanf("%d",&s[i]);
        maxLen[i]=1;
    }
    for(int i=2;i<=N;i++)
        for(int j=1;j<i;j++)
            if(s[i]>s[j])
                maxLen[i]=max(maxLen[i],maxLen[j]+1);
    printf("%d",*max_element(maxLen+1,maxLen+N+1)); 
    return 0;
}

 

Direct example: Suppose a sample of this question {1,7,3,5,9,4,8}, we wish to make it are (a1, a2, a3, a4, a5, a6, a7), we it may be assumed that each time a rise in the longest sub-sequence initial value maxLen [i] = 1, because we know that every number is a sequence itself.

Then we have a1: 1, maxLen [1] = 1, and a2 = 7, maxLen [2] = 1, this time we compare a1, a2, i.e. code is s [i] and s [j], a1 <a2, described maxLen [2] may be [1] is longer than maxLen, i.e. maxLen [2] length maxLen [1] +1 (this refers to 1 plus the number a2 into this sequence, i.e. the a2 a1 back into the original of this temporary increase in the longest sub-sequences is just one element of this element [a1], now adds a A2), then i ++, this time a3 = 3, maxLen [3] = 1,

Since a3> a1, so maxLen [3] = maxLen [1] +1 (This means 1 to enter this sequence plus a3), then j ++,

Since a3 <a2, does not comply with the law LIS slightly, so maxLen [3] final = maxLen [1] + 1 = 2, so a1 a2 a3 not put back, there is no maxLen [2] +1, and so on you can find the longest rising sequences.

A little sad that the time complexity of this algorithm is O (n ^ 2), data and more will easily burst ...

 

+ + Binary search greedy dynamic regulation method:

Code (lowerbound write their own functions):

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<string.h>
#include<math.h>
using namespace std;
typedef long long LL;
const int maxn=1e5+7;
const int maxm=2e5+7;
const long long mod=1e9+7;
int N,arr[maxn],s[maxn],num=1;

int lowerbound(int i)
{
    int L=1,R=num,mid,lastPos=0;
    while(L<=R)
    {
        mid=L+(R-L)/2;
        if(s[i]>=arr[mid])
            R=mid-1;
        else
        {
            lastPos=mid;
            L=mid+1;
        } 
    }
    return lastPos;
}

int main()
{
    scanf("%d",&N);
    for(int i=1;i<=N;i++)
        scanf("%d",&s[i]);
    arr[1]=s[1];
    for(int i=2;i<=N;i++)
    {
        if(arr[num]<s[i])
            arr[++num]=s[i];
        else
            arr[lowerbound(i)]=s[i];
    }
    printf("%d",num);
    return 0;
}

 

Code(突然发现c++的函数lower_bound之后):

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<string.h>
#include<math.h>
using namespace std;
typedef long long LL;
const int maxn=1e5+7;
const int maxm=2e5+7;
const long long mod=1e9+7;
int N,arr[maxn],s[maxn],num=1;
int main() 
{
    scanf("%d",&N);
    for(int i=1;i<=N;i++)
        scanf("%d",&s[i]);
    arr[1]=s[1];
    for(int i=2;i<=N;i++)
    {
        if(arr[num]<s[i])
            arr[++num]=s[i];
        else
            *(lower_bound(arr+1,arr+num+1,s[i]))=s[i];
    }
    printf("%d",num);
    return 0;
}

 

依然是要举栗子,假设这个这道题的样例是{5,3,4,1,8},这一眼也能看出最长上升子数列是3,

,我们不妨令它分别为 (a1, a2, a3, a4, a5,),重点它来了它来了!!我们这时候要开一个新的数组arr[ ]存放子数列,原来的数组是s[1]=5,s[2]=3,s[3]=4,s[4]=1,s[5]=8。

一开始我们让num=1,然后将s[1]=5的值赋给arr[1],此时子数列为{5},接着比较s[2]与arr[1]的大小(即s[i]和arr[num]的大小),因为s[2]<arr[1],所以此时子数列变为{3},接着比较arr[1]与s[3],s[3]>arr[1]=3,所以直接将s[3]放在arr[1]的后方,arr[2](arr[++num])=s[3]的值,此时子数列为{3,4},接着arr[2]>s[4],1比3和4都小,但是我们是想要的是保证这个子数列的数尽可能的小一些可以放更多的数进来(贪心),达到最长上升子数列目的,所以我们从arr这个数组中找出第一个比s[4]大的元素,也就是3,将3替换掉,得到当前子数列为{1,4}。因为arr[2]<s[5],直接将8放在arr[3]就完成了这个过程。

 

直接用动规来解时间复杂度会是O(n^2),但是用了二分查找之后就会变成O(nlogn),数据庞大的时候可想而知是第二种方法更优一些....

为了代码更加的整洁,我把自己在代码的注释给去掉了嘻嘻~

 

 

Guess you like

Origin www.cnblogs.com/K2MnO4/p/12244527.html