最长递增子序列(Longest Increasing Subsequence)

1. 问题描述

有一个序列 A = a[1:n], 若存在一个数列bm,其中对于任何1 < i < m ,满足bi < bi+1 且 abi < abi+1 ,则称abn为an的一个递增子序列
试求出给定序列的最长递增子序列长度。

 

2. 动态规划解

用 opt[i] 表示 A[1 : i] 的 以 Ai 为末位元素的最长递增子序列的长度,则

  • opt[1] = 1
  • 如果存在 1 <= j  < i, 使得 Aj < Ai, 则 opt[i] = max {opt[j] + 1 | 1 <= j < i, Aj < Ai}
  • 如果 Ai < Aj( for all 1 <=j <i), 则 opt[i] = 1

3. c++实现

// Longest Increasing Sequence
template<class Iter, class Compare>
int LIS(Iter beg, Iter end, Compare op)
{
    if(beg == end) return 0;
    
    int n = end - beg;
    std::vector<int> opt(n);

    opt[0] = 1;
    Iter id = std::next(beg);
    for(int i = 1; i < n; ++i, ++id)
    {
        opt[i] = 1;
        Iter iter = beg;
        for(int j = 0; j < i; ++iter, ++j)
            if(op(*iter, *id) && opt[i] < opt[j] + 1 )
                opt[i] = opt[j] + 1;
    }

    int length_opt = std::accumulate(opt.begin(), opt.end(), 0, [](int a, int b){return a > b ? a : b;});
    return length_opt;
}

template<class Iter>
int LIS(Iter beg, Iter end)
{
    return LIS(beg, end, std::less<decltype(*beg)>());
}
    

4. 分析

时间复杂度 O(n^2)

空间复杂度 O(n)

 

5. O(n * lg(n))解法

生成数组 B , B[i] 存放 A 的所有的长度为 i 的递增子序列中,最末位元素的最小值。

template<class Iter, class Compare>
int LIS2(Iter beg, Iter end, Compare op)
{
    if(beg == end) return 0;

    std::vector<typename std::iterator_traits<Iter>::value_type> B;
    B.reserve(end - beg);
    B.push_back(*beg++);
    for(; beg != end; ++beg)
    {
        auto it = std::upper_bound(B.begin(), B.end(), *beg, op);
        if(it != B.end())
            *it = *beg;
        else
            B.push_back(*beg);
    }
    return B.size();
}

template<class Iter>
int LIS2(Iter beg, Iter end)
{
    return LIS2(beg, end, std::less<decltype(*beg)>());
}

 

posted @ 2013-09-21 07:15  半亩梨花  阅读(261)  评论(0)    收藏  举报