• (算法)最长递增子序列


    问题:

    Given an array of N integer, find the length of the longest increasing subsequence.

    For example, given [1,-5,4,5,10,-1,-5,7], the longest increasing subsequence is length 4.(1,4,510)

    思路:

    1、枚举

    枚举数组所有的子序列,然后判断它们是否为递增子序列(回溯法)。

    2、转化

    将数组排序,然后找出新数组和旧数组的最长公共子序列LCS。

    (关于最长公共子序列,参考:http://www.cnblogs.com/AndyJee/p/4469196.html)

    3、动态规划

    假设数组为A,len[i] 表示以第 i 个元素为结尾(即第i个元素为最大)的最长递增子序列的长度;

    求len[i],可以先求以前面i-1个元素结尾的最长递增子序列,如果A[i]比前面A[0...i-1]中某个元素k小,那么就可以在相应的len[k]上加1,当然是最大的len[k];

    详见http://blog.csdn.net/kenby/article/details/6804720

    4、优化

    上述方法在求len[i]的时候, 要从a[1], ... a[i-1]中找出所有比 a[i] 小的元素,而a[1], ... a[i-1]是无序的,查找速度比较慢。

    引出数组 f[k] 表示长度等于k的递增子序列中最末尾的元素, 长度越长的序列,其末尾元素也越大,所以f[k]是递增的。

    实例 <1, 3, 4, 2, 7>

    len[1] = 1, f[1] = a[1] = 1

    len[2] = 2, f[2] = a[2] = 3

    len[3] = 3, f[3] = a[3] = 4

    len[4] = 2, f[2] = a[4] = 2 ( 更新了f[2] )

    那么,如何求len[5] 呢?

    f[1] = 1, f[2] = 2, f[3] = 4, a[5] = 7,

    找出末尾元素比a[5]小,而且长度最长的递增子序列,此例中,

    f[3] = 4 表示长度等于3的子序列,其末尾元素为4,这个子序列的长度最长。

    a[5]加上此序列形成的新序列长度为4, 然后更新f[4] = a[5] = 7,表示长度等于4的子序列,其末尾元素等于7

    在上面的步骤中,找出末尾元素比a[i]小,而且长度最长的子序列,其实就是对于f[1], ...f[k], 从后往前找,第一个比a[i]小的元素就是长度最长的子序列。查找的时候可以用二分查找方法,故更快。

    代码:

    1、动态规划

    #include <iostream>
    #include <vector>
    using namespace std;
    
    unsigned int LISS(const int array[], size_t length, vector<int> &result)
    {
        unsigned int liss[length];
        unsigned int pre[length];
    
        for(int i=0;i<length;++i){
            liss[i]=1;
            pre[i]=i;
        }
    
        int k=0;
        int max=1;
        for(int i=1;i<length;++i){
            for(int j=0;j<i;++j){
                if(array[j]<array[i] && liss[j]+1>liss[i]){
                    liss[i]=liss[j]+1;
                    pre[i]=j;
    
                    if(max<liss[i]){
                        max=liss[i];
                        k=i;
                    }
                }
            }
        }
    
    //    i = max - 1;
        while(pre[k]!=k){
    //        result[i--] = array[k];
            result.push_back(array[k]);
            k=pre[k];
        }
        //result[i] = array[k];
        result.push_back(array[k]);
        return max;
    }
    
    
    int main()
    {
        int A[]={1,-5,4,5,10,-1,-5,7};
        int len=sizeof(A)/sizeof(A[0]);
        vector<int> result;
    
        cout << LISS(A,len,result) << endl;
        for(int i=0;i<result.size();i++)
            cout<<result[i]<<' ';
        cout<<endl;
    }
    

    2、优化

    #include <iostream>
    #include <vector>
    using namespace std;
    
    unsigned int LISS(const int array[], size_t length, vector<int> &result)
    {
        unsigned int liss[length];
        unsigned int pre[length];
        unsigned int f[length];
    
        for(int i=0;i<length;++i){
            liss[i]=1;
            pre[i]=i;
            f[i]=0;
        }
    
        int k=0;
        int max=1;
        f[max]=0;
    
        for(int i=1;i<length;++i){
            for(int j=max;j>=1;--j){
                if(array[f[j]]<array[i]){
                    liss[i]=j+1;
                    pre[i]=f[j];
    
                    if(f[liss[i]]!=0){
                        int old=array[f[liss[i]]];
                        if(array[i]<old)
                            f[liss[i]]=i;
                    }
                    else
                        f[liss[i]]=i;
    
                    if(max<liss[i]){
                        max=liss[i];
                        k=i;
                    }
                    break;
                }
            }
        }
    
    //    i = max - 1;
        while(pre[k]!=k){
    //        result[i--] = array[k];
            result.push_back(array[k]);
            k=pre[k];
        }
        //result[i] = array[k];
        result.push_back(array[k]);
        return max;
    }
    
    
    int main()
    {
        int A[]={1,3,4,2,7};
        int len=sizeof(A)/sizeof(A[0]);
        vector<int> result;
    
        cout << LISS(A,len,result) << endl;
        for(int i=0;i<result.size();i++)
            cout<<result[i]<<' ';
        cout<<endl;
    }

    在线测试OJ:

    http://www.nowcoder.com/questionTerminal/585d46a1447b4064b749f08c2ab9ce66

    AC代码:

    class AscentSequence {
    public:
        int findLongest(vector<int> A, int n) {
            vector<int> dp(n);
            vector<int> f(n);
            
            dp[0]=1;
            f[0]=A[0];
            
            int left,right,mid;
            int count=0;
            int lmax=1;
            for(int i=1;i<n;i++){
                left=0;
                right=count;
                while(left<=right){
                    mid=left+((right-left)>>1);
                    if(A[i]>=f[mid])
                        left=mid+1;
                    else
                        right=mid-1;
                }
                
                f[left]=A[i];
                if(left>count)
                    count=left;
                
                dp[i]=left+1;
                
                if(lmax<dp[i])
                    lmax=dp[i];
            }
            
            return lmax;       
        }
    };
    class AscentSequence {
    public:
        int findLongest(vector<int> A, int n) {
            int len=A.size();
            if(len<=1)
                return len;
            
            vector<int> mLen(n,1);
            int lMax=1;
            for(int i=1;i<n;i++){
                for(int j=0;j<i;j++){
                    if(A[i]>A[j] && mLen[j]+1>mLen[i])
                        mLen[i]=mLen[j]+1;
                    if(mLen[i]>lMax)
                        lMax=mLen[i];
                }
            }
            
            return lMax;
        }
    };
  • 相关阅读:
    接口隔离原则(Interface Segregation Principle)ISP
    依赖倒置(Dependence Inversion Principle)DIP
    里氏替换原则(Liskov Substitution Principle) LSP
    单一指责原则(Single Responsibility Principle) SRP
    《面向对象葵花宝典》阅读笔记
    智能手表ticwatch穿戴体验
    我所理解的软件工程
    RBAC基于角色的权限访问控制
    程序员健康指南阅读笔记
    我晕倒在厕所了
  • 原文地址:https://www.cnblogs.com/AndyJee/p/4703332.html
Copyright © 2020-2023  润新知